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

Commit 9a1fcdfd authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

[MTD] NAND Signal that a bitflip was corrected by ECC



Return -EUCLEAN on read when a bitflip was detected and corrected, so the
clients can react and eventually copy the affected block to a spare one.
Make all in kernel users aware of the change.

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 8593fbc6
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -355,7 +355,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
		ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +
				(block * SECTORSIZE), SECTORSIZE, &retlen,
				movebuf);
		if (ret < 0) {
		if (ret < 0 && ret != -EUCLEAN) {
			ret = mtd->read(mtd,
					(inftl->EraseSize * BlockMap[block]) +
					(block * SECTORSIZE), SECTORSIZE,
@@ -922,7 +922,10 @@ foundit:
	} else {
		size_t retlen;
		loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
		if (mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer))
		int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);

		/* Handle corrected bit flips gracefully */
		if (ret < 0 && ret != -EUCLEAN)
			return -EIO;
	}
	return 0;
+4 −1
Original line number Diff line number Diff line
@@ -199,10 +199,13 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
		/* Nand returns -EBADMSG on ecc errors, but it returns
		 * the data. For our userspace tools it is important
		 * to dump areas with ecc errors !
		 * For kernel internal usage it also might return -EUCLEAN
		 * to signal the caller that a bitflip has occured and has
		 * been corrected by the ECC algorithm.
		 * Userspace software which accesses NAND this way
		 * must be aware of the fact that it deals with NAND
		 */
		if (!ret || (ret == -EBADMSG)) {
		if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) {
			*ppos += retlen;
			if (copy_to_user(buf, kbuf, retlen)) {
				kfree(kbuf);
+12 −3
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
	    size_t * retlen, u_char * buf)
{
	struct mtd_concat *concat = CONCAT(mtd);
	int err = -EINVAL;
	int ret = 0, err = -EINVAL;
	int i;

	*retlen = 0;
@@ -80,9 +80,18 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,

		err = subdev->read(subdev, from, size, &retsize, buf);

		if (err)
		if (err && (err != -EBADMSG) && (err != -EUCLEAN))
			break;

		/* Save information about bitflips! */
		if (err) {
			if (err == -EBADMSG)
				ret = err;
			else if (!ret)
				ret = err;
			err = 0;
		}

		*retlen += retsize;
		len -= size;
		if (len == 0)
@@ -92,7 +101,7 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
		buf += size;
		from = 0;
	}
	return err;
	return err ? err : ret;
}

static int
+4 −1
Original line number Diff line number Diff line
@@ -1035,7 +1035,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
	if (ret)
		return ret;

	return mtd->ecc_stats.failed - stats.failed ? -EBADMSG : 0;
	if (mtd->ecc_stats.failed - stats.failed)
		return -EBADMSG;

	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
}

/**
+4 −2
Original line number Diff line number Diff line
@@ -422,7 +422,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p

		ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
				512, &retlen, movebuf);
		if (ret < 0) {
		if (ret < 0 && ret != -EUCLEAN) {
			ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
					+ (block * 512), 512, &retlen,
					movebuf);
@@ -768,7 +768,9 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
	} else {
		loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
		size_t retlen;
		if (mtd->read(mtd, ptr, 512, &retlen, buffer))
		int res = mtd->read(mtd, ptr, 512, &retlen, buffer);

		if (res < 0 && res != -EUCLEAN)
			return -EIO;
	}
	return 0;
Loading