summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorMasahiro Yamada <yamada.masahiro@socionext.com>2017-03-30 02:45:51 -0400
committerBoris Brezillon <boris.brezillon@free-electrons.com>2017-04-25 08:18:33 -0400
commitd29109be2e8d4a102d8304d7b8bb0d6dfe5e1d27 (patch)
treecf4ac2900a1cc1bab880259711118228fe882ecf /drivers/mtd/nand
parent20d48595f8857c9b7e0d31d9734ebe18d63faea1 (diff)
mtd: nand: denali: fix erased page checking
This part is wrong in multiple ways: [1] is_erased() is called against "buf" twice, so the OOB area is not checked at all. The second call should check chip->oob_poi. [2] This code block is nested by double "if (check_erase_page)". The inner one is redundant. [3] The ECC_ERROR_ADDRESS register reports which sector(s) had uncorrectable ECC errors. It is pointless to check the whole page if only one sector contains errors. [4] Unfortunately, the Denali ECC correction engine has already manipulated the data buffer before it decides the bitflips are uncorrectable. That is, not all of the data are 0xFF after an erased page is processed by the ECC engine. The current is_erased() helper could report false-positive ECC errors. Actually, a certain mount of bitflips are allowed in an erased page. The core framework provides nand_check_erased_ecc_chunk() that takes the threshold into account. Let's use this. This commit reworks the code to solve those problems. Please note the erased page checking is implemented as a separate helper function instead of embedding it in the loop in handle_ecc(). The reason is that OOB data are needed for the erased page checking, but the controller can not start a new transaction until all ECC error information is read out from the registers. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/denali.c77
1 files changed, 50 insertions, 27 deletions
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index c5c150a95fb6..64a3bdcc6b04 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -818,19 +818,44 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
818 } 818 }
819} 819}
820 820
821/* 821static int denali_check_erased_page(struct mtd_info *mtd,
822 * this function examines buffers to see if they contain data that 822 struct nand_chip *chip, uint8_t *buf,
823 * indicate that the buffer is part of an erased region of flash. 823 unsigned long uncor_ecc_flags,
824 */ 824 unsigned int max_bitflips)
825static bool is_erased(uint8_t *buf, int len)
826{ 825{
827 int i; 826 uint8_t *ecc_code = chip->buffers->ecccode;
827 int ecc_steps = chip->ecc.steps;
828 int ecc_size = chip->ecc.size;
829 int ecc_bytes = chip->ecc.bytes;
830 int i, ret, stat;
831
832 ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
833 chip->ecc.total);
834 if (ret)
835 return ret;
836
837 for (i = 0; i < ecc_steps; i++) {
838 if (!(uncor_ecc_flags & BIT(i)))
839 continue;
840
841 stat = nand_check_erased_ecc_chunk(buf, ecc_size,
842 ecc_code, ecc_bytes,
843 NULL, 0,
844 chip->ecc.strength);
845 if (stat < 0) {
846 mtd->ecc_stats.failed++;
847 } else {
848 mtd->ecc_stats.corrected += stat;
849 max_bitflips = max_t(unsigned int, max_bitflips, stat);
850 }
828 851
829 for (i = 0; i < len; i++) 852 buf += ecc_size;
830 if (buf[i] != 0xFF) 853 ecc_code += ecc_bytes;
831 return false; 854 }
832 return true; 855
856 return max_bitflips;
833} 857}
858
834#define ECC_SECTOR_SIZE 512 859#define ECC_SECTOR_SIZE 512
835 860
836#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12) 861#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
@@ -841,7 +866,7 @@ static bool is_erased(uint8_t *buf, int len)
841#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO) 866#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)
842 867
843static int handle_ecc(struct mtd_info *mtd, struct denali_nand_info *denali, 868static int handle_ecc(struct mtd_info *mtd, struct denali_nand_info *denali,
844 uint8_t *buf, bool *check_erased_page) 869 uint8_t *buf, unsigned long *uncor_ecc_flags)
845{ 870{
846 unsigned int bitflips = 0; 871 unsigned int bitflips = 0;
847 unsigned int max_bitflips = 0; 872 unsigned int max_bitflips = 0;
@@ -868,11 +893,10 @@ static int handle_ecc(struct mtd_info *mtd, struct denali_nand_info *denali,
868 893
869 if (ECC_ERROR_UNCORRECTABLE(err_cor_info)) { 894 if (ECC_ERROR_UNCORRECTABLE(err_cor_info)) {
870 /* 895 /*
871 * if the error is not correctable, need to look at the 896 * Check later if this is a real ECC error, or
872 * page to see if it is an erased page. if so, then 897 * an erased sector.
873 * it's not a real ECC error
874 */ 898 */
875 *check_erased_page = true; 899 *uncor_ecc_flags |= BIT(err_sector);
876 } else if (err_byte < ECC_SECTOR_SIZE) { 900 } else if (err_byte < ECC_SECTOR_SIZE) {
877 /* 901 /*
878 * If err_byte is larger than ECC_SECTOR_SIZE, means error 902 * If err_byte is larger than ECC_SECTOR_SIZE, means error
@@ -1045,7 +1069,6 @@ static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
1045static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, 1069static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
1046 uint8_t *buf, int oob_required, int page) 1070 uint8_t *buf, int oob_required, int page)
1047{ 1071{
1048 unsigned int max_bitflips = 0;
1049 struct denali_nand_info *denali = mtd_to_denali(mtd); 1072 struct denali_nand_info *denali = mtd_to_denali(mtd);
1050 1073
1051 dma_addr_t addr = denali->buf.dma_buf; 1074 dma_addr_t addr = denali->buf.dma_buf;
@@ -1053,7 +1076,8 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
1053 1076
1054 uint32_t irq_status; 1077 uint32_t irq_status;
1055 uint32_t irq_mask = INTR__ECC_TRANSACTION_DONE | INTR__ECC_ERR; 1078 uint32_t irq_mask = INTR__ECC_TRANSACTION_DONE | INTR__ECC_ERR;
1056 bool check_erased_page = false; 1079 unsigned long uncor_ecc_flags = 0;
1080 int stat = 0;
1057 1081
1058 if (page != denali->page) { 1082 if (page != denali->page) {
1059 dev_err(denali->dev, 1083 dev_err(denali->dev,
@@ -1078,21 +1102,20 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
1078 memcpy(buf, denali->buf.buf, mtd->writesize); 1102 memcpy(buf, denali->buf.buf, mtd->writesize);
1079 1103
1080 if (irq_status & INTR__ECC_ERR) 1104 if (irq_status & INTR__ECC_ERR)
1081 max_bitflips = handle_ecc(mtd, denali, buf, &check_erased_page); 1105 stat = handle_ecc(mtd, denali, buf, &uncor_ecc_flags);
1082 denali_enable_dma(denali, false); 1106 denali_enable_dma(denali, false);
1083 1107
1084 if (check_erased_page) { 1108 if (stat < 0)
1109 return stat;
1110
1111 if (uncor_ecc_flags) {
1085 read_oob_data(mtd, chip->oob_poi, denali->page); 1112 read_oob_data(mtd, chip->oob_poi, denali->page);
1086 1113
1087 /* check ECC failures that may have occurred on erased pages */ 1114 stat = denali_check_erased_page(mtd, chip, buf,
1088 if (check_erased_page) { 1115 uncor_ecc_flags, stat);
1089 if (!is_erased(buf, mtd->writesize))
1090 mtd->ecc_stats.failed++;
1091 if (!is_erased(buf, mtd->oobsize))
1092 mtd->ecc_stats.failed++;
1093 }
1094 } 1116 }
1095 return max_bitflips; 1117
1118 return stat;
1096} 1119}
1097 1120
1098static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, 1121static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,