aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Pargmann <mpa@pengutronix.de>2016-04-25 08:35:12 -0400
committerBoris Brezillon <boris.brezillon@free-electrons.com>2016-05-05 17:55:15 -0400
commitbd2e778c9ee361c23ccb2b10591712e129d97893 (patch)
tree46aeaee89254eb0ebe24fbe567db405fa66628c2
parent32698aafc9f0c6373b240f15a91fefb65c55907c (diff)
gpmi-nand: Handle ECC Errors in erased pages
ECC is only calculated for written pages. As erased pages are not actively written the ECC is always invalid. For this purpose the Hardware BCH unit is able to check for erased pages and does not raise an ECC error in this case. This behaviour can be influenced using the BCH_MODE register which sets the number of allowed bitflips in an erased page. Unfortunately the unit is not capable of fixing the bitflips in memory. To avoid complete software checks for erased pages, we can simply check buffers with uncorrectable ECC errors because we know that any erased page with errors is uncorrectable by the BCH unit. This patch adds the generic nand_check_erased_ecc_chunk() to gpmi-nand to correct erased pages. To have the valid data in the buffer before using them, this patch moves the read_page_swap_end() call before the ECC status checking for-loop. Signed-off-by: Markus Pargmann <mpa@pengutronix.de> [Squashed patches by Stefan and Boris to check ECC area] Tested-by: Stefan Christ <s.christ@phytec.de> Acked-by: Han xu <han.xu@nxp.com> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c78
1 files changed, 73 insertions, 5 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 798ed5961e8f..6e461560c6a8 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1064,14 +1064,87 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
1064 /* Loop over status bytes, accumulating ECC status. */ 1064 /* Loop over status bytes, accumulating ECC status. */
1065 status = auxiliary_virt + nfc_geo->auxiliary_status_offset; 1065 status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
1066 1066
1067 read_page_swap_end(this, buf, nfc_geo->payload_size,
1068 this->payload_virt, this->payload_phys,
1069 nfc_geo->payload_size,
1070 payload_virt, payload_phys);
1071
1067 for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) { 1072 for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
1068 if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED)) 1073 if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
1069 continue; 1074 continue;
1070 1075
1071 if (*status == STATUS_UNCORRECTABLE) { 1076 if (*status == STATUS_UNCORRECTABLE) {
1077 int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
1078 u8 *eccbuf = this->raw_buffer;
1079 int offset, bitoffset;
1080 int eccbytes;
1081 int flips;
1082
1083 /* Read ECC bytes into our internal raw_buffer */
1084 offset = nfc_geo->metadata_size * 8;
1085 offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
1086 offset -= eccbits;
1087 bitoffset = offset % 8;
1088 eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
1089 offset /= 8;
1090 eccbytes -= offset;
1091 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
1092 chip->read_buf(mtd, eccbuf, eccbytes);
1093
1094 /*
1095 * ECC data are not byte aligned and we may have
1096 * in-band data in the first and last byte of
1097 * eccbuf. Set non-eccbits to one so that
1098 * nand_check_erased_ecc_chunk() does not count them
1099 * as bitflips.
1100 */
1101 if (bitoffset)
1102 eccbuf[0] |= GENMASK(bitoffset - 1, 0);
1103
1104 bitoffset = (bitoffset + eccbits) % 8;
1105 if (bitoffset)
1106 eccbuf[eccbytes - 1] |= GENMASK(7, bitoffset);
1107
1108 /*
1109 * The ECC hardware has an uncorrectable ECC status
1110 * code in case we have bitflips in an erased page. As
1111 * nothing was written into this subpage the ECC is
1112 * obviously wrong and we can not trust it. We assume
1113 * at this point that we are reading an erased page and
1114 * try to correct the bitflips in buffer up to
1115 * ecc_strength bitflips. If this is a page with random
1116 * data, we exceed this number of bitflips and have a
1117 * ECC failure. Otherwise we use the corrected buffer.
1118 */
1119 if (i == 0) {
1120 /* The first block includes metadata */
1121 flips = nand_check_erased_ecc_chunk(
1122 buf + i * nfc_geo->ecc_chunk_size,
1123 nfc_geo->ecc_chunk_size,
1124 eccbuf, eccbytes,
1125 auxiliary_virt,
1126 nfc_geo->metadata_size,
1127 nfc_geo->ecc_strength);
1128 } else {
1129 flips = nand_check_erased_ecc_chunk(
1130 buf + i * nfc_geo->ecc_chunk_size,
1131 nfc_geo->ecc_chunk_size,
1132 eccbuf, eccbytes,
1133 NULL, 0,
1134 nfc_geo->ecc_strength);
1135 }
1136
1137 if (flips > 0) {
1138 max_bitflips = max_t(unsigned int, max_bitflips,
1139 flips);
1140 mtd->ecc_stats.corrected += flips;
1141 continue;
1142 }
1143
1072 mtd->ecc_stats.failed++; 1144 mtd->ecc_stats.failed++;
1073 continue; 1145 continue;
1074 } 1146 }
1147
1075 mtd->ecc_stats.corrected += *status; 1148 mtd->ecc_stats.corrected += *status;
1076 max_bitflips = max_t(unsigned int, max_bitflips, *status); 1149 max_bitflips = max_t(unsigned int, max_bitflips, *status);
1077 } 1150 }
@@ -1091,11 +1164,6 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
1091 chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; 1164 chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
1092 } 1165 }
1093 1166
1094 read_page_swap_end(this, buf, nfc_geo->payload_size,
1095 this->payload_virt, this->payload_phys,
1096 nfc_geo->payload_size,
1097 payload_virt, payload_phys);
1098
1099 return max_bitflips; 1167 return max_bitflips;
1100} 1168}
1101 1169