Skip to content

Commit

Permalink
driver: nand: empty sector 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 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.

Signed-off-by: Kai Stuhlemmer (ebee Engineering) <[email protected]>
  • Loading branch information
ksdd committed Mar 17, 2021
1 parent af59b26 commit ff3c66d
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 ff3c66d

Please sign in to comment.