[PATCH 1/2] mtd: nand: add erased-page bitflip correction
Huang Shijie
b32955 at freescale.com
Wed Mar 12 04:06:07 EDT 2014
On Tue, Mar 11, 2014 at 02:11:51AM -0700, Brian Norris wrote:
> +static int nand_verify_erased_page(struct mtd_info *mtd, uint8_t *buf, int page)
> +{
> + struct nand_chip *chip = mtd->priv;
> + int i, oobbits, databits;
> + uint8_t *data = buf, *oob = chip->oob_poi;
> + unsigned int max_bitflips = 0;
> + int oob_step = mtd->oobsize / chip->ecc.steps;
> + int ret;
> +
> + oobbits = oob_step * 8;
> + databits = chip->ecc.size * 8;
> +
> + /* read without ECC for verification */
> + ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
> + if (ret)
> + return ret;
> +
> + /* Check each ECC step individually */
> + for (i = 0; i < chip->ecc.steps; i++) {
> + unsigned int flips = databits + oobbits;
> +
> + flips -= bitmap_weight((unsigned long *)oob, oobbits);
> + flips -= bitmap_weight((unsigned long *)data, databits);
> +
> + /* Too many bitflips */
> + if (flips > chip->ecc.strength)
> + return -EBADMSG;
> +
> + max_bitflips = max(max_bitflips, flips);
> +
> + data += chip->ecc.size;
The gpmi uses a NAND layout like this:
* +---+----------+-+----------+-+----------+-+----------+-+
* | M | data |E| data |E| data |E| data |E|
* +---+----------+-+----------+-+----------+-+----------+-+
M : The metadata, which is 10 by default.
E : The ECC parity for "data" or "data + M".
If you want to count each sector, it makes the code very complicated. :(
> + oob += oob_step;
> + }
> +
> + pr_debug("correcting bitflips in erased page (max %u)\n",
> + max_bitflips);
> +
> + memset(buf, 0xff, mtd->writesize);
> + memset(oob, 0xff, mtd->oobsize);
> +
> + return max_bitflips;
> +}
> +/**
> * nand_do_read_ops - [INTERN] Read data with ECC
> * @mtd: MTD device structure
> * @from: offset to read from
> @@ -1554,6 +1610,18 @@ read_retry:
> break;
> }
>
> + /* Check an ECC error for 0xff + bitflips? */
> + if ((chip->options & NAND_ECC_NEED_CHECK_FF) &&
> + mtd->ecc_stats.failed - ecc_failures) {
> + ret = nand_verify_erased_page(mtd, bufpoi,
> + page);
I think we can merge this code into the read-retry check like:
---------------------------------------------
if (mtd->ecc_stats.failed - ecc_failures) {
// step 1: count the bitflips, assume N.
N = bitflips_count();
// step 2:
if (N < ecc_strength) {
do the erase-page-check;
} else
do the read-retry.
if (retry_mode + 1 <= chip->read_retries) {
retry_mode++;
ret = nand_setup_read_retry(mtd,
retry_mode);
if (ret < 0)
break;
/* Reset failures; retry */
mtd->ecc_stats.failed = ecc_failures;
goto read_retry;
} else {
/* No more retry modes; real failure */
ecc_fail = true;
}
}
---------------------------------------------
thanks
Huang Shijie
More information about the linux-mtd
mailing list