[PATCH 3/3] nand: atmel: Correct bitflips in erased pages

Tudor Ambarus tudor.ambarus at microchip.com
Fri May 21 10:52:06 CEST 2021


From: "Kai Stuhlemmer (ebee Engineering)" <kai.stuhlemmer at ebee.de>

Not correcting anything in case of empty ECC data area
is not an appropriate strategy, because an uncorrected bit-flip
in an empty sector may cause upper layers (namely UBI) fail to work
properly. Therefore the approach chosen in Linux kernel and other
u-boot mtd drivers has been adopted, where a heuristic implemented
by nand_check_erased_ecc_chunk() is used in order to detect and
correct empty sectors.

Tested with sama5d3_xplained and sam9x60-ek.

Signed-off-by: Kai Stuhlemmer (ebee Engineering) <kai.stuhlemmer at ebee.de>
Tested-by: Tudor Ambarus <tudor.ambarus at microchip.com>
[ta: reorder if conditions, change commit subject, s/uint8_t/u8.]
Signed-off-by: Tudor Ambarus <tudor.ambarus at microchip.com>
---
 drivers/mtd/nand/raw/atmel_nand.c | 37 +++++++++++++++----------------
 1 file changed, 18 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/raw/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c
index abc432c862..6541c3bea8 100644
--- a/drivers/mtd/nand/raw/atmel_nand.c
+++ b/drivers/mtd/nand/raw/atmel_nand.c
@@ -493,21 +493,9 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
 {
 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
 	struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
-	int i, err_nbr, eccbytes;
-	uint8_t *buf_pos;
-
-	/* SAMA5D4 PMECC IP can correct errors for all 0xff page */
-	if (host->pmecc_version >= PMECC_VERSION_SAMA5D4)
-		goto normal_check;
-
-	eccbytes = nand_chip->ecc.bytes;
-	for (i = 0; i < eccbytes; i++)
-		if (ecc[i] != 0xff)
-			goto normal_check;
-	/* Erased page, return OK */
-	return 0;
+	int i, err_nbr;
+	u8 *buf_pos, *ecc_pos;
 
-normal_check:
 	for (i = 0; i < host->pmecc_sector_number; i++) {
 		err_nbr = 0;
 		if (pmecc_stat & 0x1) {
@@ -518,15 +506,26 @@ normal_check:
 			pmecc_get_sigma(mtd);
 
 			err_nbr = pmecc_err_location(mtd);
-			if (err_nbr == -1) {
+			if (err_nbr >= 0) {
+				pmecc_correct_data(mtd, buf_pos, ecc, i,
+						   host->pmecc_bytes_per_sector,
+						   err_nbr);
+			} else if (host->pmecc_version < PMECC_VERSION_SAMA5D4) {
+				ecc_pos = ecc + i * host->pmecc_bytes_per_sector;
+
+				err_nbr = nand_check_erased_ecc_chunk(
+					buf_pos, host->pmecc_sector_size,
+					ecc_pos, host->pmecc_bytes_per_sector,
+					NULL, 0, host->pmecc_corr_cap);
+			}
+
+			if (err_nbr < 0) {
 				dev_err(mtd->dev, "PMECC: Too many errors\n");
 				mtd->ecc_stats.failed++;
 				return -EBADMSG;
-			} else {
-				pmecc_correct_data(mtd, buf_pos, ecc, i,
-					host->pmecc_bytes_per_sector, err_nbr);
-				mtd->ecc_stats.corrected += err_nbr;
 			}
+
+			mtd->ecc_stats.corrected += err_nbr;
 		}
 		pmecc_stat >>= 1;
 	}
-- 
2.25.1



More information about the U-Boot mailing list