145 lines
4.4 KiB
Diff
145 lines
4.4 KiB
Diff
From 26d82e0081aa6f0c7db5e4bb5b154b7c528cb8d6 Mon Sep 17 00:00:00 2001
|
|
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
|
Date: Thu, 14 Nov 2013 18:25:39 -0300
|
|
Subject: [PATCH 153/203] mtd: nand: pxa3xx: Add ECC BCH correctable errors
|
|
detection
|
|
|
|
This commit extends the ECC correctable error detection to include
|
|
ECC BCH errors. The number of BCH correctable errors can be any up to 16,
|
|
and the actual value is exposed in the NDSR register.
|
|
|
|
Therefore, we change some symbol names to refer to correctable or
|
|
uncorrectable (instead of single-bit or double-bit as it was in the
|
|
Hamming case) and while at it, cleanup the detection code slightly.
|
|
|
|
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
|
Tested-by: Daniel Mack <zonque@gmail.com>
|
|
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
|
---
|
|
drivers/mtd/nand/pxa3xx_nand.c | 57 ++++++++++++++++++++++++++----------------
|
|
1 file changed, 35 insertions(+), 22 deletions(-)
|
|
|
|
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
|
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
|
@@ -85,6 +85,9 @@
|
|
#define NDCR_INT_MASK (0xFFF)
|
|
|
|
#define NDSR_MASK (0xfff)
|
|
+#define NDSR_ERR_CNT_OFF (16)
|
|
+#define NDSR_ERR_CNT_MASK (0x1f)
|
|
+#define NDSR_ERR_CNT(sr) ((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK)
|
|
#define NDSR_RDY (0x1 << 12)
|
|
#define NDSR_FLASH_RDY (0x1 << 11)
|
|
#define NDSR_CS0_PAGED (0x1 << 10)
|
|
@@ -93,8 +96,8 @@
|
|
#define NDSR_CS1_CMDD (0x1 << 7)
|
|
#define NDSR_CS0_BBD (0x1 << 6)
|
|
#define NDSR_CS1_BBD (0x1 << 5)
|
|
-#define NDSR_DBERR (0x1 << 4)
|
|
-#define NDSR_SBERR (0x1 << 3)
|
|
+#define NDSR_UNCORERR (0x1 << 4)
|
|
+#define NDSR_CORERR (0x1 << 3)
|
|
#define NDSR_WRDREQ (0x1 << 2)
|
|
#define NDSR_RDDREQ (0x1 << 1)
|
|
#define NDSR_WRCMDREQ (0x1)
|
|
@@ -135,9 +138,9 @@ enum {
|
|
ERR_NONE = 0,
|
|
ERR_DMABUSERR = -1,
|
|
ERR_SENDCMD = -2,
|
|
- ERR_DBERR = -3,
|
|
+ ERR_UNCORERR = -3,
|
|
ERR_BBERR = -4,
|
|
- ERR_SBERR = -5,
|
|
+ ERR_CORERR = -5,
|
|
};
|
|
|
|
enum {
|
|
@@ -221,6 +224,8 @@ struct pxa3xx_nand_info {
|
|
unsigned int oob_size;
|
|
unsigned int spare_size;
|
|
unsigned int ecc_size;
|
|
+ unsigned int ecc_err_cnt;
|
|
+ unsigned int max_bitflips;
|
|
int retcode;
|
|
|
|
/* cached register value */
|
|
@@ -571,10 +576,25 @@ static irqreturn_t pxa3xx_nand_irq(int i
|
|
|
|
status = nand_readl(info, NDSR);
|
|
|
|
- if (status & NDSR_DBERR)
|
|
- info->retcode = ERR_DBERR;
|
|
- if (status & NDSR_SBERR)
|
|
- info->retcode = ERR_SBERR;
|
|
+ if (status & NDSR_UNCORERR)
|
|
+ info->retcode = ERR_UNCORERR;
|
|
+ if (status & NDSR_CORERR) {
|
|
+ info->retcode = ERR_CORERR;
|
|
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 &&
|
|
+ info->ecc_bch)
|
|
+ info->ecc_err_cnt = NDSR_ERR_CNT(status);
|
|
+ else
|
|
+ info->ecc_err_cnt = 1;
|
|
+
|
|
+ /*
|
|
+ * Each chunk composing a page is corrected independently,
|
|
+ * and we need to store maximum number of corrected bitflips
|
|
+ * to return it to the MTD layer in ecc.read_page().
|
|
+ */
|
|
+ info->max_bitflips = max_t(unsigned int,
|
|
+ info->max_bitflips,
|
|
+ info->ecc_err_cnt);
|
|
+ }
|
|
if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {
|
|
/* whether use dma to transfer data */
|
|
if (info->use_dma) {
|
|
@@ -672,6 +692,7 @@ static void prepare_start_command(struct
|
|
info->use_ecc = 0;
|
|
info->use_spare = 1;
|
|
info->retcode = ERR_NONE;
|
|
+ info->ecc_err_cnt = 0;
|
|
info->ndcb3 = 0;
|
|
|
|
switch (command) {
|
|
@@ -1053,26 +1074,18 @@ static int pxa3xx_nand_read_page_hwecc(s
|
|
{
|
|
struct pxa3xx_nand_host *host = mtd->priv;
|
|
struct pxa3xx_nand_info *info = host->info_data;
|
|
- int max_bitflips = 0;
|
|
|
|
chip->read_buf(mtd, buf, mtd->writesize);
|
|
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
|
|
|
- if (info->retcode == ERR_SBERR) {
|
|
- switch (info->use_ecc) {
|
|
- case 1:
|
|
- max_bitflips = 1;
|
|
- mtd->ecc_stats.corrected++;
|
|
- break;
|
|
- case 0:
|
|
- default:
|
|
- break;
|
|
- }
|
|
- } else if (info->retcode == ERR_DBERR) {
|
|
+ if (info->retcode == ERR_CORERR && info->use_ecc) {
|
|
+ mtd->ecc_stats.corrected += info->ecc_err_cnt;
|
|
+
|
|
+ } else if (info->retcode == ERR_UNCORERR) {
|
|
/*
|
|
* for blank page (all 0xff), HW will calculate its ECC as
|
|
* 0, which is different from the ECC information within
|
|
- * OOB, ignore such double bit errors
|
|
+ * OOB, ignore such uncorrectable errors
|
|
*/
|
|
if (is_buf_blank(buf, mtd->writesize))
|
|
info->retcode = ERR_NONE;
|
|
@@ -1080,7 +1093,7 @@ static int pxa3xx_nand_read_page_hwecc(s
|
|
mtd->ecc_stats.failed++;
|
|
}
|
|
|
|
- return max_bitflips;
|
|
+ return info->max_bitflips;
|
|
}
|
|
|
|
static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
|