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: Boris Brezillon <boris.brezillon@free-electrons.com> Tested-by: Franklin S Cooper Jr. <fcooper@ti.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
This commit is contained in:
parent
6f357de854
commit
6e9411923b
@ -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,
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
/* Uncorrectable error */
|
/* Uncorrectable error */
|
||||||
return -1;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -391,7 +391,7 @@ compare:
|
|||||||
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,
|
|||||||
} 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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
} 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,
|
|||||||
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 */
|
|||||||
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 */
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
/* 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 {
|
|||||||
* @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
|
|||||||
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 *
|
||||||
|
Loading…
x
Reference in New Issue
Block a user