mtd: nand: brcmnand: fix mtd corrected bits stat
Currently we attempt to get the amount of flipped bits from a hardware location which is reset on every subpage. Instead obtain total flipped bits stat from hardware accumulator. In addition identify the correct maximum subpage corrected bits. Signed-off-by: David Regan <dregan@broadcom.com> Reviewed-by: William Zhang <william.zhang@broadcom.com> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
This commit is contained in:
committed by
Miquel Raynal
parent
79e441ee47
commit
23584da287
@@ -360,6 +360,7 @@ enum brcmnand_reg {
|
||||
BRCMNAND_CORR_THRESHOLD_EXT,
|
||||
BRCMNAND_UNCORR_COUNT,
|
||||
BRCMNAND_CORR_COUNT,
|
||||
BRCMNAND_READ_ERROR_COUNT,
|
||||
BRCMNAND_CORR_EXT_ADDR,
|
||||
BRCMNAND_CORR_ADDR,
|
||||
BRCMNAND_UNCORR_EXT_ADDR,
|
||||
@@ -390,6 +391,7 @@ static const u16 brcmnand_regs_v21[] = {
|
||||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0,
|
||||
[BRCMNAND_CORR_COUNT] = 0,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x60,
|
||||
[BRCMNAND_CORR_ADDR] = 0x64,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x68,
|
||||
@@ -420,6 +422,7 @@ static const u16 brcmnand_regs_v33[] = {
|
||||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0,
|
||||
[BRCMNAND_CORR_COUNT] = 0,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x80,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x70,
|
||||
[BRCMNAND_CORR_ADDR] = 0x74,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x78,
|
||||
@@ -450,6 +453,7 @@ static const u16 brcmnand_regs_v50[] = {
|
||||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0,
|
||||
[BRCMNAND_CORR_COUNT] = 0,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x80,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x70,
|
||||
[BRCMNAND_CORR_ADDR] = 0x74,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x78,
|
||||
@@ -480,6 +484,7 @@ static const u16 brcmnand_regs_v60[] = {
|
||||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0xc4,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0xfc,
|
||||
[BRCMNAND_CORR_COUNT] = 0x100,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x104,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x10c,
|
||||
[BRCMNAND_CORR_ADDR] = 0x110,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x114,
|
||||
@@ -510,6 +515,7 @@ static const u16 brcmnand_regs_v71[] = {
|
||||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0xe0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0xfc,
|
||||
[BRCMNAND_CORR_COUNT] = 0x100,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x104,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x10c,
|
||||
[BRCMNAND_CORR_ADDR] = 0x110,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x114,
|
||||
@@ -540,6 +546,7 @@ static const u16 brcmnand_regs_v72[] = {
|
||||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0xe0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0xfc,
|
||||
[BRCMNAND_CORR_COUNT] = 0x100,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x104,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x10c,
|
||||
[BRCMNAND_CORR_ADDR] = 0x110,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x114,
|
||||
@@ -960,11 +967,11 @@ static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
|
||||
return offs_cs0 + cs * ctrl->reg_spacing + cs_offs;
|
||||
}
|
||||
|
||||
static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl)
|
||||
static inline u32 brcmnand_corr_total(struct brcmnand_controller *ctrl)
|
||||
{
|
||||
if (ctrl->nand_version < 0x0600)
|
||||
return 1;
|
||||
return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT);
|
||||
if (ctrl->nand_version < 0x400)
|
||||
return 0;
|
||||
return brcmnand_read_reg(ctrl, BRCMNAND_READ_ERROR_COUNT);
|
||||
}
|
||||
|
||||
static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
|
||||
@@ -2067,15 +2074,20 @@ static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
|
||||
*/
|
||||
static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
u64 addr, unsigned int trans, u32 *buf,
|
||||
u8 *oob, u64 *err_addr)
|
||||
u8 *oob, u64 *err_addr, unsigned int *corr)
|
||||
{
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
int i, ret = 0;
|
||||
unsigned int prev_corr;
|
||||
|
||||
if (corr)
|
||||
*corr = 0;
|
||||
|
||||
brcmnand_clear_ecc_addr(ctrl);
|
||||
|
||||
for (i = 0; i < trans; i++, addr += FC_BYTES) {
|
||||
prev_corr = brcmnand_corr_total(ctrl);
|
||||
brcmnand_set_cmd_addr(mtd, addr);
|
||||
/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
|
||||
brcmnand_send_cmd(host, CMD_PAGE_READ);
|
||||
@@ -2100,13 +2112,16 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
|
||||
if (*err_addr)
|
||||
ret = -EBADMSG;
|
||||
}
|
||||
else {
|
||||
*err_addr = brcmnand_get_correcc_addr(ctrl);
|
||||
|
||||
if (!ret) {
|
||||
*err_addr = brcmnand_get_correcc_addr(ctrl);
|
||||
if (*err_addr) {
|
||||
ret = -EUCLEAN;
|
||||
|
||||
if (*err_addr)
|
||||
ret = -EUCLEAN;
|
||||
if (corr && (brcmnand_corr_total(ctrl) - prev_corr) > *corr)
|
||||
*corr = brcmnand_corr_total(ctrl) - prev_corr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2174,6 +2189,8 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int err;
|
||||
bool retry = true;
|
||||
bool edu_err = false;
|
||||
unsigned int corrected = 0; /* max corrected bits per subpage */
|
||||
unsigned int prev_tot = brcmnand_corr_total(ctrl);
|
||||
|
||||
dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
|
||||
|
||||
@@ -2201,9 +2218,11 @@ try_dmaread:
|
||||
memset(oob, 0x99, mtd->oobsize);
|
||||
|
||||
err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
|
||||
oob, &err_addr);
|
||||
oob, &err_addr, &corrected);
|
||||
}
|
||||
|
||||
mtd->ecc_stats.corrected += brcmnand_corr_total(ctrl) - prev_tot;
|
||||
|
||||
if (mtd_is_eccerr(err)) {
|
||||
/*
|
||||
* On controller version and 7.0, 7.1 , DMA read after a
|
||||
@@ -2241,16 +2260,20 @@ try_dmaread:
|
||||
}
|
||||
|
||||
if (mtd_is_bitflip(err)) {
|
||||
unsigned int corrected = brcmnand_count_corrected(ctrl);
|
||||
|
||||
/* in case of EDU correctable error we read again using PIO */
|
||||
if (edu_err)
|
||||
err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
|
||||
oob, &err_addr);
|
||||
oob, &err_addr, &corrected);
|
||||
|
||||
dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
|
||||
(unsigned long long)err_addr);
|
||||
mtd->ecc_stats.corrected += corrected;
|
||||
/*
|
||||
* if flipped bits accumulator is not supported but we detected
|
||||
* a correction, increase stat by 1 to match previous behavior.
|
||||
*/
|
||||
if (brcmnand_corr_total(ctrl) == prev_tot)
|
||||
mtd->ecc_stats.corrected++;
|
||||
|
||||
/* Always exceed the software-imposed threshold */
|
||||
return max(mtd->bitflip_threshold, corrected);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user