Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d062d4ed authored by Mike Dunn's avatar Mike Dunn Committed by David Woodhouse
Browse files

mtd: bitflip_threshold added to mtd_info and sysfs

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: default avatarMike Dunn <mikedunn@newsguy.com>
Signed-off-by: default avatarArtem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent a9b672e8
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -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.
+33 −0
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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;

+9 −0
Original line number Diff line number Diff line
@@ -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;