Skip to content

Commit

Permalink
atmel_nand.c: Empty page error correction fixed.
Browse files Browse the repository at this point in the history
Not correcting anything in case of empty ECC data area
is not an appropriate strategy, because an uncorrected bit-flip
in an empty page may cause upper layers (namely UBI) fail to work
properly. Therefor 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 pages.
  • Loading branch information
ksdd committed Mar 17, 2021
1 parent af59b26 commit ba874cc
Showing 1 changed file with 22 additions and 17 deletions.
39 changes: 22 additions & 17 deletions drivers/mtd/nand/raw/atmel_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,21 +484,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;
uint8_t *buf_pos, *ecc_pos;

normal_check:
for (i = 0; i < host->pmecc_sector_number; i++) {
err_nbr = 0;
if (pmecc_stat & 0x1) {
Expand All @@ -510,9 +498,26 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,

err_nbr = pmecc_err_location(mtd);
if (err_nbr == -1) {
dev_err(host->dev, "PMECC: Too many errors\n");
mtd->ecc_stats.failed++;
return -EBADMSG;
/* SAMA5D4 PMECC IP can correct errors for all 0xff page */
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 * 3) / 4);

if (err_nbr < 0) {
dev_err(host->dev, "PMECC: Too many errors\n");
mtd->ecc_stats.failed++;
return -EBADMSG;
}
mtd->ecc_stats.corrected += err_nbr;
} else {
dev_err(host->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);
Expand Down

0 comments on commit ba874cc

Please sign in to comment.