summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
authorKai Stuhlemmer (ebee Engineering) <kai.stuhlemmer@ebee.de>2021-05-21 11:52:06 +0300
committerEugen Hristev <eugen.hristev@microchip.com>2021-06-07 11:01:40 +0300
commit32cc2368f816bf21e5e5ffc6070a8abcd8d3e02d (patch)
tree698c2d996311494e20b1c7aa0daa9a8309dc526e /drivers/mtd
parent55661ee0e3cf518e1b89939f00fda50b326d3139 (diff)
downloadu-boot-32cc2368f816bf21e5e5ffc6070a8abcd8d3e02d.tar.xz
nand: atmel: Correct bitflips in erased pages
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@ebee.de> Tested-by: Tudor Ambarus <tudor.ambarus@microchip.com> [ta: reorder if conditions, change commit subject, s/uint8_t/u8.] Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/raw/atmel_nand.c37
1 files 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;
}