From d3a69599a0207d930692cf5a0d33a6b6e7803527 Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Wed, 25 Apr 2012 12:06:08 -0700 Subject: [PATCH] --- yaml --- r: 310207 b: refs/heads/master c: d062d4ede877fcd2ecc4c6262abad09a6f32950a h: refs/heads/master i: 310205: 25d889691ce671103960bca79449c358b02b872d 310203: 513dc9ec13050c4903493573f82da06341de8868 310199: bd1497a7eb10c589f496711bc16dc9cf98fffe0f 310191: 552082c8bb99517b718f7c9814f463410a5c1336 310175: ce161eec2d2bd92b7041571c3a531fcb198bb08d 310143: fa6aa7d8bb44a341b707b69e4100944adba88a9f v: v3 --- [refs] | 2 +- .../Documentation/ABI/testing/sysfs-class-mtd | 36 +++++++++++++++++++ trunk/drivers/mtd/mtdcore.c | 33 +++++++++++++++++ trunk/drivers/mtd/mtdpart.c | 2 ++ trunk/include/linux/mtd/mtd.h | 9 +++++ 5 files changed, 81 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index e8c4b5899243..d896626a1804 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: a9b672e82bca47bf2b37ee869b8095000cf3ca88 +refs/heads/master: d062d4ede877fcd2ecc4c6262abad09a6f32950a diff --git a/trunk/Documentation/ABI/testing/sysfs-class-mtd b/trunk/Documentation/ABI/testing/sysfs-class-mtd index 43d18180b46e..78835080856a 100644 --- a/trunk/Documentation/ABI/testing/sysfs-class-mtd +++ b/trunk/Documentation/ABI/testing/sysfs-class-mtd @@ -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. + +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. diff --git a/trunk/drivers/mtd/mtdcore.c b/trunk/drivers/mtd/mtdcore.c index 090e849d3dcd..6a7cba1e24e6 100644 --- a/trunk/drivers/mtd/mtdcore.c +++ b/trunk/drivers/mtd/mtdcore.c @@ -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 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, @@ -270,6 +298,7 @@ static struct attribute *mtd_attrs[] = { &dev_attr_numeraseregions.attr, &dev_attr_name.attr, &dev_attr_ecc_strength.attr, + &dev_attr_bitflip_threshold.attr, NULL, }; @@ -332,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 diff --git a/trunk/drivers/mtd/mtdpart.c b/trunk/drivers/mtd/mtdpart.c index 9651c06de0a9..ec75d44e0253 100644 --- a/trunk/drivers/mtd/mtdpart.c +++ b/trunk/drivers/mtd/mtdpart.c @@ -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.bitflip_threshold = master->bitflip_threshold; + if (master->_block_isbad) { uint64_t offs = 0; diff --git a/trunk/include/linux/mtd/mtd.h b/trunk/include/linux/mtd/mtd.h index cd0119d19cd9..63dadc0dfb62 100644 --- a/trunk/include/linux/mtd/mtd.h +++ b/trunk/include/linux/mtd/mtd.h @@ -157,6 +157,15 @@ struct mtd_info { 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;