diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-class-mtd | 36 | ||||
-rw-r--r-- | drivers/mtd/mtdcore.c | 33 | ||||
-rw-r--r-- | drivers/mtd/mtdpart.c | 2 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 9 |
4 files changed, 80 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-mtd b/Documentation/ABI/testing/sysfs-class-mtd index 43d18180b46e..78835080856a 100644 --- a/Documentation/ABI/testing/sysfs-class-mtd +++ b/Documentation/ABI/testing/sysfs-class-mtd | |||
@@ -135,3 +135,39 @@ Description: | |||
135 | have multiple ecc steps within each writesize region. | 135 | have multiple ecc steps within each writesize region. |
136 | 136 | ||
137 | In the case of devices lacking any ECC capability, it is 0. | 137 | In the case of devices lacking any ECC capability, it is 0. |
138 | |||
139 | What: /sys/class/mtd/mtdX/bitflip_threshold | ||
140 | Date: April 2012 | ||
141 | KernelVersion: 3.4 | ||
142 | Contact: linux-mtd@lists.infradead.org | ||
143 | Description: | ||
144 | This allows the user to examine and adjust the criteria by which | ||
145 | mtd returns -EUCLEAN from mtd_read(). If the maximum number of | ||
146 | bit errors that were corrected on any single region comprising | ||
147 | an ecc step (as reported by the driver) equals or exceeds this | ||
148 | value, -EUCLEAN is returned. Otherwise, absent an error, 0 is | ||
149 | returned. Higher layers (e.g., UBI) use this return code as an | ||
150 | indication that an erase block may be degrading and should be | ||
151 | scrutinized as a candidate for being marked as bad. | ||
152 | |||
153 | The initial value may be specified by the flash device driver. | ||
154 | If not, then the default value is ecc_strength. | ||
155 | |||
156 | The introduction of this feature brings a subtle change to the | ||
157 | meaning of the -EUCLEAN return code. Previously, it was | ||
158 | interpreted to mean simply "one or more bit errors were | ||
159 | corrected". Its new interpretation can be phrased as "a | ||
160 | dangerously high number of bit errors were corrected on one or | ||
161 | more regions comprising an ecc step". The precise definition of | ||
162 | "dangerously high" can be adjusted by the user with | ||
163 | bitflip_threshold. Users are discouraged from doing this, | ||
164 | however, unless they know what they are doing and have intimate | ||
165 | knowledge of the properties of their device. Broadly speaking, | ||
166 | bitflip_threshold should be low enough to detect genuine erase | ||
167 | block degradation, but high enough to avoid the consequences of | ||
168 | a persistent return value of -EUCLEAN on devices where sticky | ||
169 | bitflips occur. Note that if bitflip_threshold exceeds | ||
170 | ecc_strength, -EUCLEAN is never returned by the read functions. | ||
171 | |||
172 | This is generally applicable only to NAND flash devices with ECC | ||
173 | capability. It is ignored on devices lacking ECC capability. | ||
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 090e849d3dcd..6a7cba1e24e6 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
@@ -259,6 +259,34 @@ static ssize_t mtd_ecc_strength_show(struct device *dev, | |||
259 | } | 259 | } |
260 | static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL); | 260 | static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL); |
261 | 261 | ||
262 | static ssize_t mtd_bitflip_threshold_show(struct device *dev, | ||
263 | struct device_attribute *attr, | ||
264 | char *buf) | ||
265 | { | ||
266 | struct mtd_info *mtd = dev_get_drvdata(dev); | ||
267 | |||
268 | return snprintf(buf, PAGE_SIZE, "%u\n", mtd->bitflip_threshold); | ||
269 | } | ||
270 | |||
271 | static ssize_t mtd_bitflip_threshold_store(struct device *dev, | ||
272 | struct device_attribute *attr, | ||
273 | const char *buf, size_t count) | ||
274 | { | ||
275 | struct mtd_info *mtd = dev_get_drvdata(dev); | ||
276 | unsigned int bitflip_threshold; | ||
277 | int retval; | ||
278 | |||
279 | retval = kstrtouint(buf, 0, &bitflip_threshold); | ||
280 | if (retval) | ||
281 | return retval; | ||
282 | |||
283 | mtd->bitflip_threshold = bitflip_threshold; | ||
284 | return count; | ||
285 | } | ||
286 | static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR, | ||
287 | mtd_bitflip_threshold_show, | ||
288 | mtd_bitflip_threshold_store); | ||
289 | |||
262 | static struct attribute *mtd_attrs[] = { | 290 | static struct attribute *mtd_attrs[] = { |
263 | &dev_attr_type.attr, | 291 | &dev_attr_type.attr, |
264 | &dev_attr_flags.attr, | 292 | &dev_attr_flags.attr, |
@@ -270,6 +298,7 @@ static struct attribute *mtd_attrs[] = { | |||
270 | &dev_attr_numeraseregions.attr, | 298 | &dev_attr_numeraseregions.attr, |
271 | &dev_attr_name.attr, | 299 | &dev_attr_name.attr, |
272 | &dev_attr_ecc_strength.attr, | 300 | &dev_attr_ecc_strength.attr, |
301 | &dev_attr_bitflip_threshold.attr, | ||
273 | NULL, | 302 | NULL, |
274 | }; | 303 | }; |
275 | 304 | ||
@@ -332,6 +361,10 @@ int add_mtd_device(struct mtd_info *mtd) | |||
332 | mtd->index = i; | 361 | mtd->index = i; |
333 | mtd->usecount = 0; | 362 | mtd->usecount = 0; |
334 | 363 | ||
364 | /* default value if not set by driver */ | ||
365 | if (mtd->bitflip_threshold == 0) | ||
366 | mtd->bitflip_threshold = mtd->ecc_strength; | ||
367 | |||
335 | if (is_power_of_2(mtd->erasesize)) | 368 | if (is_power_of_2(mtd->erasesize)) |
336 | mtd->erasesize_shift = ffs(mtd->erasesize) - 1; | 369 | mtd->erasesize_shift = ffs(mtd->erasesize) - 1; |
337 | else | 370 | else |
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 9651c06de0a9..ec75d44e0253 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -517,6 +517,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, | |||
517 | 517 | ||
518 | slave->mtd.ecclayout = master->ecclayout; | 518 | slave->mtd.ecclayout = master->ecclayout; |
519 | slave->mtd.ecc_strength = master->ecc_strength; | 519 | slave->mtd.ecc_strength = master->ecc_strength; |
520 | slave->mtd.bitflip_threshold = master->bitflip_threshold; | ||
521 | |||
520 | if (master->_block_isbad) { | 522 | if (master->_block_isbad) { |
521 | uint64_t offs = 0; | 523 | uint64_t offs = 0; |
522 | 524 | ||
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index cd0119d19cd9..63dadc0dfb62 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
@@ -157,6 +157,15 @@ struct mtd_info { | |||
157 | unsigned int erasesize_mask; | 157 | unsigned int erasesize_mask; |
158 | unsigned int writesize_mask; | 158 | unsigned int writesize_mask; |
159 | 159 | ||
160 | /* | ||
161 | * read ops return -EUCLEAN if max number of bitflips corrected on any | ||
162 | * one region comprising an ecc step equals or exceeds this value. | ||
163 | * Settable by driver, else defaults to ecc_strength. User can override | ||
164 | * in sysfs. N.B. The meaning of the -EUCLEAN return code has changed; | ||
165 | * see Documentation/ABI/testing/sysfs-class-mtd for more detail. | ||
166 | */ | ||
167 | unsigned int bitflip_threshold; | ||
168 | |||
160 | // Kernel-only stuff starts here. | 169 | // Kernel-only stuff starts here. |
161 | const char *name; | 170 | const char *name; |
162 | int index; | 171 | int index; |