mtd: bitflip_threshold added to mtd_info and sysfs
authorMike Dunn <mikedunn@newsguy.com>
Wed, 25 Apr 2012 19:06:08 +0000 (12:06 -0700)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Mon, 14 May 2012 04:11:39 +0000 (23:11 -0500)
An element 'bitflip_threshold' is added to struct mtd_info, and also exposed as
a read/write variable in sysfs.  This will be used to determine whether or not
mtd_read() returns -EUCLEAN or 0 (absent a hard error).  If the driver leaves it
as zero, mtd will set it to a default value of ecc_strength.

This v2 adds the line that propagates bitflip_threshold from the master to the
partitions - thanks Ivan¹.

¹ http://lists.infradead.org/pipermail/linux-mtd/2012-April/040900.html

Signed-off-by: Mike Dunn <mikedunn@newsguy.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Documentation/ABI/testing/sysfs-class-mtd
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
include/linux/mtd/mtd.h

index 43d18180b46ed54e32765af0fbb85a1e0819432e..78835080856a9dc17df3b40857bb2dfa08d54277 100644 (file)
@@ -135,3 +135,39 @@ Description:
                have multiple ecc steps within each writesize region.
 
                In the case of devices lacking any ECC capability, it is 0.
                have multiple ecc steps within each writesize region.
 
                In the case of devices lacking any ECC capability, it is 0.
+
+What:          /sys/class/mtd/mtdX/bitflip_threshold
+Date:          April 2012
+KernelVersion: 3.4
+Contact:       linux-mtd@lists.infradead.org
+Description:
+               This allows the user to examine and adjust the criteria by which
+               mtd returns -EUCLEAN from mtd_read().  If the maximum number of
+               bit errors that were corrected on any single region comprising
+               an ecc step (as reported by the driver) equals or exceeds this
+               value, -EUCLEAN is returned.  Otherwise, absent an error, 0 is
+               returned.  Higher layers (e.g., UBI) use this return code as an
+               indication that an erase block may be degrading and should be
+               scrutinized as a candidate for being marked as bad.
+
+               The initial value may be specified by the flash device driver.
+               If not, then the default value is ecc_strength.
+
+               The introduction of this feature brings a subtle change to the
+               meaning of the -EUCLEAN return code.  Previously, it was
+               interpreted to mean simply "one or more bit errors were
+               corrected".  Its new interpretation can be phrased as "a
+               dangerously high number of bit errors were corrected on one or
+               more regions comprising an ecc step".  The precise definition of
+               "dangerously high" can be adjusted by the user with
+               bitflip_threshold.  Users are discouraged from doing this,
+               however, unless they know what they are doing and have intimate
+               knowledge of the properties of their device.  Broadly speaking,
+               bitflip_threshold should be low enough to detect genuine erase
+               block degradation, but high enough to avoid the consequences of
+               a persistent return value of -EUCLEAN on devices where sticky
+               bitflips occur.  Note that if bitflip_threshold exceeds
+               ecc_strength, -EUCLEAN is never returned by the read functions.
+
+               This is generally applicable only to NAND flash devices with ECC
+               capability.  It is ignored on devices lacking ECC capability.
index 090e849d3dcdbb7792a767116971812e3d21624e..6a7cba1e24e61fbff8965744923005e18c835319 100644 (file)
@@ -259,6 +259,34 @@ static ssize_t mtd_ecc_strength_show(struct device *dev,
 }
 static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL);
 
 }
 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,
 static struct attribute *mtd_attrs[] = {
        &dev_attr_type.attr,
        &dev_attr_flags.attr,
@@ -270,6 +298,7 @@ static struct attribute *mtd_attrs[] = {
        &dev_attr_numeraseregions.attr,
        &dev_attr_name.attr,
        &dev_attr_ecc_strength.attr,
        &dev_attr_numeraseregions.attr,
        &dev_attr_name.attr,
        &dev_attr_ecc_strength.attr,
+       &dev_attr_bitflip_threshold.attr,
        NULL,
 };
 
        NULL,
 };
 
@@ -332,6 +361,10 @@ int add_mtd_device(struct mtd_info *mtd)
        mtd->index = i;
        mtd->usecount = 0;
 
        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
        if (is_power_of_2(mtd->erasesize))
                mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
        else
index 9651c06de0a9298f4db58265524ecaebe2c2b9b4..ec75d44e0253c3885df7aa90764ead18e027dca9 100644 (file)
@@ -517,6 +517,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 
        slave->mtd.ecclayout = master->ecclayout;
        slave->mtd.ecc_strength = master->ecc_strength;
 
        slave->mtd.ecclayout = master->ecclayout;
        slave->mtd.ecc_strength = master->ecc_strength;
+       slave->mtd.bitflip_threshold = master->bitflip_threshold;
+
        if (master->_block_isbad) {
                uint64_t offs = 0;
 
        if (master->_block_isbad) {
                uint64_t offs = 0;
 
index cd0119d19cd9bce1d6ae43962ed0a0b1e1f3fd41..63dadc0dfb629a74f6e578a16255ffc4cdb4d56a 100644 (file)
@@ -157,6 +157,15 @@ struct mtd_info {
        unsigned int erasesize_mask;
        unsigned int writesize_mask;
 
        unsigned int erasesize_mask;
        unsigned int writesize_mask;
 
+       /*
+        * read ops return -EUCLEAN if max number of bitflips corrected on any
+        * one region comprising an ecc step equals or exceeds this value.
+        * Settable by driver, else defaults to ecc_strength.  User can override
+        * in sysfs.  N.B. The meaning of the -EUCLEAN return code has changed;
+        * see Documentation/ABI/testing/sysfs-class-mtd for more detail.
+        */
+       unsigned int bitflip_threshold;
+
        // Kernel-only stuff starts here.
        const char *name;
        int index;
        // Kernel-only stuff starts here.
        const char *name;
        int index;
This page took 0.030657 seconds and 5 git commands to generate.