]> Pileus Git - ~andy/linux/blobdiff - drivers/mtd/mtdcore.c
Merge branch 'samsung/boards' into next/dt2
[~andy/linux] / drivers / mtd / mtdcore.c
index c837507dfb1c73021da2a47eebd975bd40573ef9..575730744fdb3ce83dc8e4a78cf65cefb3413fdc 100644 (file)
@@ -250,6 +250,43 @@ static ssize_t mtd_name_show(struct device *dev,
 }
 static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL);
 
+static ssize_t mtd_ecc_strength_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_strength);
+}
+static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL);
+
+static ssize_t mtd_bitflip_threshold_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", mtd->bitflip_threshold);
+}
+
+static ssize_t mtd_bitflip_threshold_store(struct device *dev,
+                                          struct device_attribute *attr,
+                                          const char *buf, size_t count)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+       unsigned int bitflip_threshold;
+       int retval;
+
+       retval = kstrtouint(buf, 0, &bitflip_threshold);
+       if (retval)
+               return retval;
+
+       mtd->bitflip_threshold = bitflip_threshold;
+       return count;
+}
+static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR,
+                  mtd_bitflip_threshold_show,
+                  mtd_bitflip_threshold_store);
+
 static struct attribute *mtd_attrs[] = {
        &dev_attr_type.attr,
        &dev_attr_flags.attr,
@@ -260,6 +297,8 @@ static struct attribute *mtd_attrs[] = {
        &dev_attr_oobsize.attr,
        &dev_attr_numeraseregions.attr,
        &dev_attr_name.attr,
+       &dev_attr_ecc_strength.attr,
+       &dev_attr_bitflip_threshold.attr,
        NULL,
 };
 
@@ -322,6 +361,10 @@ int add_mtd_device(struct mtd_info *mtd)
        mtd->index = i;
        mtd->usecount = 0;
 
+       /* default value if not set by driver */
+       if (mtd->bitflip_threshold == 0)
+               mtd->bitflip_threshold = mtd->ecc_strength;
+
        if (is_power_of_2(mtd->erasesize))
                mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
        else
@@ -757,12 +800,24 @@ EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
 int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
             u_char *buf)
 {
+       int ret_code;
        *retlen = 0;
        if (from < 0 || from > mtd->size || len > mtd->size - from)
                return -EINVAL;
        if (!len)
                return 0;
-       return mtd->_read(mtd, from, len, retlen, buf);
+
+       /*
+        * In the absence of an error, drivers return a non-negative integer
+        * representing the maximum number of bitflips that were corrected on
+        * any one ecc region (if applicable; zero otherwise).
+        */
+       ret_code = mtd->_read(mtd, from, len, retlen, buf);
+       if (unlikely(ret_code < 0))
+               return ret_code;
+       if (mtd->ecc_strength == 0)
+               return 0;       /* device lacks ecc */
+       return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
 }
 EXPORT_SYMBOL_GPL(mtd_read);