Commit bc468fa6a8dcfbe809eef7efe90150afbeca2fac
Committed by
Ye Li
1 parent
b4a15f89ed
Exists in
smarc_8mq_lf_v2020.04
and in
4 other branches
MLK-12693-1 nand: mxs: fix the bitflips for erased page when uncorrectable error
This patch is porting from linux: http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/commit/?h=imx_4.1.15_1.0.0_ga&id=3d42fcece496224fde59f9343763fb2dfc5b0768 " We may meet the bitflips in reading an erased page(contains all 0xFF), this may causes the UBIFS corrupt, please see the log from Elie: ----------------------------------------------------------------- [ 3.831323] UBI warning: ubi_io_read: error -74 (ECC error) while reading 16384 bytes from PEB 443:245760, read only 16384 bytes, retry [ 3.845026] UBI warning: ubi_io_read: error -74 (ECC error) while reading 16384 bytes from PEB 443:245760, read only 16384 bytes, retry [ 3.858710] UBI warning: ubi_io_read: error -74 (ECC error) while reading 16384 bytes from PEB 443:245760, read only 16384 bytes, retry [ 3.872408] UBI error: ubi_io_read: error -74 (ECC error) while reading 16384 bytes from PEB 443:245760, read 16384 bytes ... [ 4.011529] UBIFS error (pid 36): ubifs_recover_leb: corrupt empty space LEB 27:237568, corruption starts at 9815 [ 4.021897] UBIFS error (pid 36): ubifs_scanned_corruption: corruption at LEB 27:247383 [ 4.030000] UBIFS error (pid 36): ubifs_scanned_corruption: first 6569 bytes from LEB 27:247383 ----------------------------------------------------------------- This patch does a check for the uncorrectable failure in the following steps: [0] set the threshold. The threshold is set based on the truth: "A single 0 bit will lead to gf_len(13 or 14) bits 0 after the BCH do the ECC." For the sake of safe, we will set the threshold with half the gf_len, and do not make it bigger the ECC strength. [1] count the bitflips of the current ECC chunk, assume it is N. [2] if the (N <= threshold) is true, we continue to read out the page with ECC disabled. and we count the bitflips again, assume it is N2. (We read out the whole page, not just a chunk, this makes the check more strictly, and make the code more simple.) [3] if the (N2 <= threshold) is true again, we can regard this is a erased page. This is because a real erased page is full of 0xFF(maybe also has several bitflips), while a page contains the 0xFF data will definitely has many bitflips in the ECC parity areas. [4] if the [3] fails, we can regard this is a page filled with the '0xFF' data. " Signed-off-by: Peng Fan <peng.fan@nxp.com> (cherry picked from commit ceb324a2914487aa517a6c70a06a20b5e3438fda) (cherry picked from commit 026751697e41c7376414a8716cf0ea4bf998b85f) (cherry picked from commit 93b481f07b8cb59c733f420bebea77ac484f9036) (cherry picked from commit eefb30b8e68d522bd315ed884c36cb9b7e917f71)
Showing 1 changed file with 44 additions and 0 deletions Side-by-side Diff
drivers/mtd/nand/raw/mxs_nand.c
... | ... | @@ -612,6 +612,45 @@ |
612 | 612 | return buf; |
613 | 613 | } |
614 | 614 | |
615 | +static bool mxs_nand_erased_page(struct mtd_info *mtd, struct nand_chip *nand, | |
616 | + uint8_t *buf, int chunk, int page) | |
617 | +{ | |
618 | + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); | |
619 | + struct bch_geometry *geo = &nand_info->bch_geometry; | |
620 | + unsigned int flip_bits = 0, flip_bits_noecc = 0; | |
621 | + unsigned int threshold; | |
622 | + unsigned int base = geo->ecc_chunkn_size * chunk; | |
623 | + uint32_t *dma_buf = (uint32_t *)buf; | |
624 | + int i; | |
625 | + | |
626 | + threshold = geo->gf_len / 2; | |
627 | + if (threshold > geo->ecc_strength) | |
628 | + threshold = geo->ecc_strength; | |
629 | + | |
630 | + for (i = 0; i < geo->ecc_chunkn_size; i++) { | |
631 | + flip_bits += hweight8(~buf[base + i]); | |
632 | + if (flip_bits > threshold) | |
633 | + return false; | |
634 | + } | |
635 | + | |
636 | + nand->cmdfunc(mtd, NAND_CMD_READ0, 0, page); | |
637 | + nand->read_buf(mtd, buf, mtd->writesize); | |
638 | + | |
639 | + for (i = 0; i < mtd->writesize / 4; i++) { | |
640 | + flip_bits_noecc += hweight32(~dma_buf[i]); | |
641 | + if (flip_bits_noecc > threshold) | |
642 | + return false; | |
643 | + } | |
644 | + | |
645 | + mtd->ecc_stats.corrected += flip_bits; | |
646 | + | |
647 | + memset(buf, 0xff, mtd->writesize); | |
648 | + | |
649 | + printf("The page(%d) is an erased page(%d,%d,%d,%d).\n", page, chunk, threshold, flip_bits, flip_bits_noecc); | |
650 | + | |
651 | + return true; | |
652 | +} | |
653 | + | |
615 | 654 | /* |
616 | 655 | * Read a page from NAND. |
617 | 656 | */ |
... | ... | @@ -715,6 +754,8 @@ |
715 | 754 | goto rtn; |
716 | 755 | } |
717 | 756 | |
757 | + mxs_nand_return_dma_descs(nand_info); | |
758 | + | |
718 | 759 | /* Invalidate caches */ |
719 | 760 | mxs_nand_inval_data_buf(nand_info); |
720 | 761 | |
... | ... | @@ -731,6 +772,9 @@ |
731 | 772 | continue; |
732 | 773 | |
733 | 774 | if (status[i] == 0xfe) { |
775 | + if (mxs_nand_erased_page(mtd, nand, | |
776 | + nand_info->data_buf, i, page)) | |
777 | + break; | |
734 | 778 | failed++; |
735 | 779 | continue; |
736 | 780 | } |