Skip to content

Commit

Permalink
mtd: nand: read_page() returns max_bitflips
Browse files Browse the repository at this point in the history
The ecc.read_page() method for nand drivers is changed to return the maximum
number of bitflips that were corrected on any one region covering an ecc step,
This patch doesn't change what the nand code returns to mtd.

This v2 includes the change to the fsl_ifc_nand driver requested by Scott¹.

¹ http://lists.infradead.org/pipermail/linux-mtd/2012-April/040883.html

Signed-off-by: Mike Dunn <mikedunn@newsguy.com>
Acked-by (freescale changes): Scott Wood <scottwood@freescale.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
Mike Dunn authored and David Woodhouse committed May 14, 2012
1 parent d062d4e commit 3f91e94
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 38 deletions.
9 changes: 6 additions & 3 deletions drivers/mtd/nand/atmel_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd,
uint8_t *oob = chip->oob_poi;
uint8_t *ecc_pos;
int stat;
unsigned int max_bitflips = 0;

/*
* Errata: ALE is incorrectly wired up to the ECC controller
Expand Down Expand Up @@ -371,18 +372,20 @@ static int atmel_nand_read_page(struct mtd_info *mtd,
/* check if there's an error */
stat = chip->ecc.correct(mtd, p, oob, NULL);

if (stat < 0)
if (stat < 0) {
mtd->ecc_stats.failed++;
else
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}

/* get back to oob start (end of page) */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);

/* read the oob */
chip->read_buf(mtd, oob, mtd->oobsize);

return 0;
return max_bitflips;
}

/*
Expand Down
4 changes: 3 additions & 1 deletion drivers/mtd/nand/bcm_umi_bch.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
uint8_t eccCalc[NAND_ECC_NUM_BYTES];
int sectorOobSize = mtd->oobsize / eccsteps;
int stat;
unsigned int max_bitflips = 0;

for (sectorIdx = 0; sectorIdx < eccsteps;
sectorIdx++, datap += eccsize) {
Expand Down Expand Up @@ -177,9 +178,10 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
}
#endif
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return 0;
return max_bitflips;
}

/****************************************************************************
Expand Down
4 changes: 3 additions & 1 deletion drivers/mtd/nand/cafe_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
{
struct cafe_priv *cafe = mtd->priv;
unsigned int max_bitflips = 0;

cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
cafe_readl(cafe, NAND_ECC_RESULT),
Expand Down Expand Up @@ -449,10 +450,11 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
} else {
dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
mtd->ecc_stats.corrected += n;
max_bitflips = max_t(unsigned int, max_bitflips, n);
}
}

return 0;
return max_bitflips;
}

static struct nand_ecclayout cafe_oobinfo_2048 = {
Expand Down
10 changes: 7 additions & 3 deletions drivers/mtd/nand/denali.c
Original file line number Diff line number Diff line change
Expand Up @@ -924,9 +924,10 @@ bool is_erased(uint8_t *buf, int len)
#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)

static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
uint32_t irq_status)
uint32_t irq_status, unsigned int *max_bitflips)
{
bool check_erased_page = false;
unsigned int bitflips = 0;

if (irq_status & INTR_STATUS__ECC_ERR) {
/* read the ECC errors. we'll ignore them for now */
Expand Down Expand Up @@ -965,6 +966,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
/* correct the ECC error */
buf[offset] ^= err_correction_value;
denali->mtd.ecc_stats.corrected++;
bitflips++;
}
} else {
/* if the error is not correctable, need to
Expand All @@ -984,6 +986,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
clear_interrupts(denali);
denali_set_intr_modes(denali, true);
}
*max_bitflips = bitflips;
return check_erased_page;
}

Expand Down Expand Up @@ -1121,6 +1124,7 @@ static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
{
unsigned int max_bitflips;
struct denali_nand_info *denali = mtd_to_denali(mtd);

dma_addr_t addr = denali->buf.dma_buf;
Expand Down Expand Up @@ -1153,7 +1157,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,

memcpy(buf, denali->buf.buf, mtd->writesize);

check_erased_page = handle_ecc(denali, buf, irq_status);
check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips);
denali_enable_dma(denali, false);

if (check_erased_page) {
Expand All @@ -1167,7 +1171,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
denali->mtd.ecc_stats.failed++;
}
}
return 0;
return max_bitflips;
}

static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
Expand Down
5 changes: 3 additions & 2 deletions drivers/mtd/nand/docg4.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
struct docg4_priv *doc = nand->priv;
void __iomem *docptr = doc->virtadr;
uint16_t status, edc_err, *buf16;
int bits_corrected = 0;

dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);

Expand Down Expand Up @@ -772,7 +773,7 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,

/* If bitflips are reported, attempt to correct with ecc */
if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
int bits_corrected = correct_data(mtd, buf, page);
bits_corrected = correct_data(mtd, buf, page);
if (bits_corrected == -EBADMSG)
mtd->ecc_stats.failed++;
else
Expand All @@ -781,7 +782,7 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
}

writew(0, docptr + DOC_DATAEND);
return 0;
return bits_corrected;
}


Expand Down
21 changes: 14 additions & 7 deletions drivers/mtd/nand/fsl_elbc_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct fsl_elbc_fcm_ctrl {
unsigned int use_mdr; /* Non zero if the MDR is to be set */
unsigned int oob; /* Non zero if operating on OOB data */
unsigned int counter; /* counter for the initializations */
unsigned int max_bitflips; /* Saved during READ0 cmd */
};

/* These map to the positions used by the FCM hardware ECC generator */
Expand Down Expand Up @@ -253,6 +254,8 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
if (chip->ecc.mode != NAND_ECC_HW)
return 0;

elbc_fcm_ctrl->max_bitflips = 0;

if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) {
uint32_t lteccr = in_be32(&lbc->lteccr);
/*
Expand All @@ -262,11 +265,16 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
* bits 28-31 are uncorrectable errors, marked elsewhere.
* for small page nand only 1 bit is used.
* if the ELBC doesn't have the lteccr register it reads 0
* FIXME: 4 bits can be corrected on NANDs with 2k pages, so
* count the number of sub-pages with bitflips and update
* ecc_stats.corrected accordingly.
*/
if (lteccr & 0x000F000F)
out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */
if (lteccr & 0x000F0000)
if (lteccr & 0x000F0000) {
mtd->ecc_stats.corrected++;
elbc_fcm_ctrl->max_bitflips = 1;
}
}

return 0;
Expand Down Expand Up @@ -743,13 +751,17 @@ static int fsl_elbc_read_page(struct mtd_info *mtd,
uint8_t *buf,
int page)
{
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;

fsl_elbc_read_buf(mtd, buf, mtd->writesize);
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);

if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++;

return 0;
return elbc_fcm_ctrl->max_bitflips;
}

/* ECC will be calculated automatically, and errors will be detected in
Expand Down Expand Up @@ -814,11 +826,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->ecc.size = 512;
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
/*
* FIXME: can hardware ecc correct 4 bitflips if page size is
* 2k? Then does hardware report number of corrections for this
* case? If so, ecc_stats reporting needs to be fixed as well.
*/
} else {
/* otherwise fall back to default software ECC */
chip->ecc.mode = NAND_ECC_SOFT;
Expand Down
9 changes: 8 additions & 1 deletion drivers/mtd/nand/fsl_ifc_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ struct fsl_ifc_nand_ctrl {
unsigned int oob; /* Non zero if operating on OOB data */
unsigned int eccread; /* Non zero for a full-page ECC read */
unsigned int counter; /* counter for the initializations */
unsigned int max_bitflips; /* Saved during READ0 cmd */
};

static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
Expand Down Expand Up @@ -262,6 +263,8 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
dev_err(priv->dev, "NAND Flash Write Protect Error\n");

nctrl->max_bitflips = 0;

if (nctrl->eccread) {
int errors;
int bufnum = nctrl->page & priv->bufnum_mask;
Expand Down Expand Up @@ -290,6 +293,9 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
}

mtd->ecc_stats.corrected += errors;
nctrl->max_bitflips = max_t(unsigned int,
nctrl->max_bitflips,
errors);
}

nctrl->eccread = 0;
Expand Down Expand Up @@ -698,6 +704,7 @@ static int fsl_ifc_read_page(struct mtd_info *mtd,
{
struct fsl_ifc_mtd *priv = chip->priv;
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;

fsl_ifc_read_buf(mtd, buf, mtd->writesize);
fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
Expand All @@ -708,7 +715,7 @@ static int fsl_ifc_read_page(struct mtd_info *mtd,
if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
mtd->ecc_stats.failed++;

return 0;
return nctrl->max_bitflips;
}

/* ECC will be calculated automatically, and errors will be detected in
Expand Down
9 changes: 6 additions & 3 deletions drivers/mtd/nand/fsmc_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
*/
uint16_t ecc_oob[7];
uint8_t *oob = (uint8_t *)&ecc_oob[0];
unsigned int max_bitflips = 0;

for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page);
Expand Down Expand Up @@ -748,13 +749,15 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
chip->ecc.calculate(mtd, p, &ecc_calc[i]);

stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0)
if (stat < 0) {
mtd->ecc_stats.failed++;
else
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}

return 0;
return max_bitflips;
}

/*
Expand Down
Loading

0 comments on commit 3f91e94

Please sign in to comment.