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

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

mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN

The drivers' _read() method, absent an error, returns a non-negative integer
indicating the maximum number of bit errors that were corrected in any one
region comprising an ecc step.  MTD returns -EUCLEAN if this is >=
bitflip_threshold, 0 otherwise.  If bitflip_threshold is zero, the comparison is
not made since these devices lack ECC and always return zero in the non-error
case (thanks Brian)¹.  Note that this is a subtle change to the driver
interface.

This and the preceding patches in this set were tested with ubi on top of the
nandsim and docg4 devices, running the ubi test io_basic from mtd-utils.

¹ http://lists.infradead.org/pipermail/linux-mtd/2012-March/040468.html



Signed-off-by: default avatarMike Dunn <mikedunn@newsguy.com>
Acked-by: default avatarRobert Jarzmik <robert.jarzmik@free.fr>
Acked-by: default avatarBrian Norris <computersforpeace@gmail.com>
Ivan Djelic <ivan.djelic@parrot.com>
Signed-off-by: default avatarArtem Bityutskiy <artem.bityutskiy@linux.intel.com>

Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent e2788c98
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -167,7 +167,10 @@ Description:
		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.
		ecc_strength, -EUCLEAN is never returned by mtd_read().
		Conversely, if bitflip_threshold is zero, -EUCLEAN is always
		returned, absent a hard error.

		This is generally applicable only to NAND flash devices with ECC
		capability.  It is ignored on devices lacking ECC capability.
		capability.  It is ignored on devices lacking ECC capability;
		i.e., devices for which ecc_strength is zero.
+4 −2
Original line number Diff line number Diff line
@@ -850,6 +850,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
	u8 *buf = ops->datbuf;
	size_t len, ooblen, nbdata, nboob;
	u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1;
	int max_bitflips = 0;

	if (buf)
		len = ops->len;
@@ -876,7 +877,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
	ret = 0;
	skip = from % DOC_LAYOUT_PAGE_SIZE;
	mutex_lock(&docg3->cascade->lock);
	while (!ret && (len > 0 || ooblen > 0)) {
	while (ret >= 0 && (len > 0 || ooblen > 0)) {
		calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
			docg3->reliable);
		nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip);
@@ -936,7 +937,8 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
			}
			if (ret > 0) {
				mtd->ecc_stats.corrected += ret;
				ret = -EUCLEAN;
				max_bitflips = max(max_bitflips, ret);
				ret = max_bitflips;
			}
		}

+13 −1
Original line number Diff line number Diff line
@@ -800,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);

+6 −6
Original line number Diff line number Diff line
@@ -67,12 +67,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
	stats = part->master->ecc_stats;
	res = part->master->_read(part->master, from + part->offset, len,
				  retlen, buf);
	if (unlikely(res)) {
		if (mtd_is_bitflip(res))
			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
		if (mtd_is_eccerr(res))
			mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
	}
	if (unlikely(mtd_is_eccerr(res)))
		mtd->ecc_stats.failed +=
			part->master->ecc_stats.failed - stats.failed;
	else
		mtd->ecc_stats.corrected +=
			part->master->ecc_stats.corrected - stats.corrected;
	return res;
}

+2 −2
Original line number Diff line number Diff line
@@ -414,7 +414,7 @@ static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
	}
	err = 0;
	if (corrected)
		err = -EUCLEAN;
		err = 1;	/* return max_bitflips per ecc step */
	if (uncorrected)
		err = -EBADMSG;
out:
@@ -446,7 +446,7 @@ static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
	}
	err = 0;
	if (corrected)
		err = -EUCLEAN;
		err = 1;	/* return max_bitflips per ecc step */
	if (uncorrected)
		err = -EBADMSG;
	return err;
Loading