Skip to content

Commit 4551e78

Browse files
KamalDasumiquelraynal
authored andcommitted
mtd: rawnand: brcmnand: ECC error handling on EDU transfers
Implement ECC correctable and uncorrectable error handling for EDU reads. If ECC correctable bitflips are encountered on EDU transfer, read page again using PIO. This is needed due to a NAND controller limitation where corrected data is not transferred to the DMA buffer on ECC error. This applies to ECC correctable errors that are reported by the controller hardware based on set number of bitflips threshold in the controller threshold register, bitflips below the threshold are corrected silently and are not reported by the controller hardware. Fixes: a5d53ad ("mtd: rawnand: brcmnand: Add support for flash-edu for dma transfers") Signed-off-by: Kamal Dasu <[email protected]> Signed-off-by: Miquel Raynal <[email protected]> Link: https://lore.kernel.org/linux-mtd/[email protected]
1 parent bee3ab8 commit 4551e78

File tree

1 file changed

+26
-0
lines changed

1 file changed

+26
-0
lines changed

drivers/mtd/nand/raw/brcmnand/brcmnand.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,6 +1918,22 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
19181918
edu_writel(ctrl, EDU_STOP, 0); /* force stop */
19191919
edu_readl(ctrl, EDU_STOP);
19201920

1921+
if (!ret && edu_cmd == EDU_CMD_READ) {
1922+
u64 err_addr = 0;
1923+
1924+
/*
1925+
* check for ECC errors here, subpage ECC errors are
1926+
* retained in ECC error address register
1927+
*/
1928+
err_addr = brcmnand_get_uncorrecc_addr(ctrl);
1929+
if (!err_addr) {
1930+
err_addr = brcmnand_get_correcc_addr(ctrl);
1931+
if (err_addr)
1932+
ret = -EUCLEAN;
1933+
} else
1934+
ret = -EBADMSG;
1935+
}
1936+
19211937
return ret;
19221938
}
19231939

@@ -2124,6 +2140,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
21242140
u64 err_addr = 0;
21252141
int err;
21262142
bool retry = true;
2143+
bool edu_err = false;
21272144

21282145
dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
21292146

@@ -2141,6 +2158,10 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
21412158
else
21422159
return -EIO;
21432160
}
2161+
2162+
if (has_edu(ctrl) && err_addr)
2163+
edu_err = true;
2164+
21442165
} else {
21452166
if (oob)
21462167
memset(oob, 0x99, mtd->oobsize);
@@ -2188,6 +2209,11 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
21882209
if (mtd_is_bitflip(err)) {
21892210
unsigned int corrected = brcmnand_count_corrected(ctrl);
21902211

2212+
/* in case of EDU correctable error we read again using PIO */
2213+
if (edu_err)
2214+
err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
2215+
oob, &err_addr);
2216+
21912217
dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
21922218
(unsigned long long)err_addr);
21932219
mtd->ecc_stats.corrected += corrected;

0 commit comments

Comments
 (0)