Commit 6e941192 authored by Boris BREZILLON's avatar Boris BREZILLON Committed by Brian Norris

mtd: nand: return consistent error codes in ecc.correct() implementations

The error code returned by the ecc.correct() are not consistent over the
all implementations.

Document the expected behavior in include/linux/mtd/nand.h and fix
offending implementations.

[Brian: this looks like a bugfix for the ECC reporting in the bf5xx_nand
driver, but we haven't seen any testing results for it]
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Tested-by: default avatarFranklin S Cooper Jr. <fcooper@ti.com>
Signed-off-by: default avatarBrian Norris <computersforpeace@gmail.com>
parent 6f357de8
...@@ -1445,7 +1445,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, ...@@ -1445,7 +1445,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
* We can't correct so many errors */ * We can't correct so many errors */
dev_dbg(host->dev, "atmel_nand : multiple errors detected." dev_dbg(host->dev, "atmel_nand : multiple errors detected."
" Unable to correct.\n"); " Unable to correct.\n");
return -EIO; return -EBADMSG;
} }
/* if there's a single bit error : we can correct it */ /* if there's a single bit error : we can correct it */
......
...@@ -252,7 +252,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, ...@@ -252,7 +252,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
*/ */
if (hweight32(syndrome[0]) == 1) { if (hweight32(syndrome[0]) == 1) {
dev_err(info->device, "ECC data was incorrect!\n"); dev_err(info->device, "ECC data was incorrect!\n");
return 1; return -EBADMSG;
} }
syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF); syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
...@@ -285,7 +285,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, ...@@ -285,7 +285,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
data = data ^ (0x1 << failing_bit); data = data ^ (0x1 << failing_bit);
*(dat + failing_byte) = data; *(dat + failing_byte) = data;
return 0; return 1;
} }
/* /*
...@@ -298,26 +298,34 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, ...@@ -298,26 +298,34 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
dev_err(info->device, dev_err(info->device,
"Please discard data, mark bad block\n"); "Please discard data, mark bad block\n");
return 1; return -EBADMSG;
} }
static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc) u_char *read_ecc, u_char *calc_ecc)
{ {
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
int ret; int ret, bitflips = 0;
ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
if (ret < 0)
return ret;
bitflips = ret;
/* If ecc size is 512, correct second 256 bytes */ /* If ecc size is 512, correct second 256 bytes */
if (chip->ecc.size == 512) { if (chip->ecc.size == 512) {
dat += 256; dat += 256;
read_ecc += 3; read_ecc += 3;
calc_ecc += 3; calc_ecc += 3;
ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
if (ret < 0)
return ret;
bitflips += ret;
} }
return ret; return bitflips;
} }
static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode) static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
......
...@@ -207,7 +207,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat, ...@@ -207,7 +207,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7); dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7);
return 1; return 1;
} else { } else {
return -1; return -EBADMSG;
} }
} else if (!(diff & (diff - 1))) { } else if (!(diff & (diff - 1))) {
/* Single bit ECC error in the ECC itself, /* Single bit ECC error in the ECC itself,
...@@ -215,7 +215,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat, ...@@ -215,7 +215,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
return 1; return 1;
} else { } else {
/* Uncorrectable error */ /* Uncorrectable error */
return -1; return -EBADMSG;
} }
} }
...@@ -391,7 +391,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd, ...@@ -391,7 +391,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
return 0; return 0;
case 1: /* five or more errors detected */ case 1: /* five or more errors detected */
davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET); davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
return -EIO; return -EBADMSG;
case 2: /* error addresses computed */ case 2: /* error addresses computed */
case 3: case 3:
num_errors = 1 + ((fsr >> 16) & 0x03); num_errors = 1 + ((fsr >> 16) & 0x03);
......
...@@ -254,7 +254,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, ...@@ -254,7 +254,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
} while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout); } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
if (timeout == 0) if (timeout == 0)
return -1; return -ETIMEDOUT;
reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
reg &= ~JZ_NAND_ECC_CTRL_ENABLE; reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
...@@ -262,7 +262,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, ...@@ -262,7 +262,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
if (status & JZ_NAND_STATUS_ERROR) { if (status & JZ_NAND_STATUS_ERROR) {
if (status & JZ_NAND_STATUS_UNCOR_ERROR) if (status & JZ_NAND_STATUS_UNCOR_ERROR)
return -1; return -EBADMSG;
error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29; error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
......
...@@ -674,7 +674,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, ...@@ -674,7 +674,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
return -1; return -EBADMSG;
} }
return 0; return 0;
...@@ -701,7 +701,7 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, ...@@ -701,7 +701,7 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
err = ecc_stat & ecc_bit_mask; err = ecc_stat & ecc_bit_mask;
if (err > err_limit) { if (err > err_limit) {
printk(KERN_WARNING "UnCorrectable RS-ECC Error\n"); printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
return -1; return -EBADMSG;
} else { } else {
ret += err; ret += err;
} }
......
...@@ -98,7 +98,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, ...@@ -98,7 +98,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
} }
} else if (count < 0) { } else if (count < 0) {
printk(KERN_ERR "ecc unrecoverable error\n"); printk(KERN_ERR "ecc unrecoverable error\n");
count = -1; count = -EBADMSG;
} }
return count; return count;
} }
......
...@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *buf, ...@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *buf,
return 1; /* error in ECC data; no action needed */ return 1; /* error in ECC data; no action needed */
pr_err("%s: uncorrectable ECC error\n", __func__); pr_err("%s: uncorrectable ECC error\n", __func__);
return -1; return -EBADMSG;
} }
EXPORT_SYMBOL(__nand_correct_data); EXPORT_SYMBOL(__nand_correct_data);
......
...@@ -826,12 +826,12 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ ...@@ -826,12 +826,12 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
case 1: case 1:
/* Uncorrectable error */ /* Uncorrectable error */
pr_debug("ECC UNCORRECTED_ERROR 1\n"); pr_debug("ECC UNCORRECTED_ERROR 1\n");
return -1; return -EBADMSG;
case 11: case 11:
/* UN-Correctable error */ /* UN-Correctable error */
pr_debug("ECC UNCORRECTED_ERROR B\n"); pr_debug("ECC UNCORRECTED_ERROR B\n");
return -1; return -EBADMSG;
case 12: case 12:
/* Correctable error */ /* Correctable error */
...@@ -861,7 +861,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ ...@@ -861,7 +861,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
return 0; return 0;
} }
pr_debug("UNCORRECTED_ERROR default\n"); pr_debug("UNCORRECTED_ERROR default\n");
return -1; return -EBADMSG;
} }
} }
......
...@@ -477,7 +477,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, ...@@ -477,7 +477,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
if (dev->dma_error) { if (dev->dma_error) {
dev->dma_error = 0; dev->dma_error = 0;
return -1; return -EIO;
} }
r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS); r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
...@@ -491,7 +491,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, ...@@ -491,7 +491,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
/* ecc uncorrectable error */ /* ecc uncorrectable error */
if (ecc_status & R852_ECC_FAIL) { if (ecc_status & R852_ECC_FAIL) {
dbg("ecc: unrecoverable error, in half %d", i); dbg("ecc: unrecoverable error, in half %d", i);
error = -1; error = -EBADMSG;
goto exit; goto exit;
} }
......
...@@ -456,7 +456,13 @@ struct nand_hw_control { ...@@ -456,7 +456,13 @@ struct nand_hw_control {
* @hwctl: function to control hardware ECC generator. Must only * @hwctl: function to control hardware ECC generator. Must only
* be provided if an hardware ECC is available * be provided if an hardware ECC is available
* @calculate: function for ECC calculation or readback from ECC hardware * @calculate: function for ECC calculation or readback from ECC hardware
* @correct: function for ECC correction, matching to ECC generator (sw/hw) * @correct: function for ECC correction, matching to ECC generator (sw/hw).
* Should return a positive number representing the number of
* corrected bitflips, -EBADMSG if the number of bitflips exceed
* ECC strength, or any other error code if the error is not
* directly related to correction.
* If -EBADMSG is returned the input buffers should be left
* untouched.
* @read_page_raw: function to read a raw page without ECC. This function * @read_page_raw: function to read a raw page without ECC. This function
* should hide the specific layout used by the ECC * should hide the specific layout used by the ECC
* controller and always return contiguous in-band and * controller and always return contiguous in-band and
......
...@@ -55,7 +55,7 @@ static inline int ...@@ -55,7 +55,7 @@ static inline int
nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc) unsigned char *read_ecc, unsigned char *calc_ecc)
{ {
return -1; return -ENOTSUPP;
} }
static inline struct nand_bch_control * static inline struct nand_bch_control *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment