mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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
					
				
					 11 changed files with 37 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -1445,7 +1445,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
 | 
			
		|||
		 * We can't correct so many errors */
 | 
			
		||||
		dev_dbg(host->dev, "atmel_nand : multiple errors detected."
 | 
			
		||||
				" Unable to correct.\n");
 | 
			
		||||
		return -EIO;
 | 
			
		||||
		return -EBADMSG;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 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) {
 | 
			
		||||
		dev_err(info->device, "ECC data was incorrect!\n");
 | 
			
		||||
		return 1;
 | 
			
		||||
		return -EBADMSG;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
		*(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,
 | 
			
		||||
		"Please discard data, mark bad block\n");
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
	return -EBADMSG;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
 | 
			
		||||
					u_char *read_ecc, u_char *calc_ecc)
 | 
			
		||||
{
 | 
			
		||||
	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);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	bitflips = ret;
 | 
			
		||||
 | 
			
		||||
	/* If ecc size is 512, correct second 256 bytes */
 | 
			
		||||
	if (chip->ecc.size == 512) {
 | 
			
		||||
		dat += 256;
 | 
			
		||||
		read_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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
				return 1;
 | 
			
		||||
			} else {
 | 
			
		||||
				return -1;
 | 
			
		||||
				return -EBADMSG;
 | 
			
		||||
			}
 | 
			
		||||
		} else if (!(diff & (diff - 1))) {
 | 
			
		||||
			/* 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;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* Uncorrectable error */
 | 
			
		||||
			return -1;
 | 
			
		||||
			return -EBADMSG;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -391,7 +391,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
 | 
			
		|||
			return 0;
 | 
			
		||||
		case 1:		/* five or more errors detected */
 | 
			
		||||
			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
 | 
			
		||||
			return -EIO;
 | 
			
		||||
			return -EBADMSG;
 | 
			
		||||
		case 2:		/* error addresses computed */
 | 
			
		||||
		case 3:
 | 
			
		||||
			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);
 | 
			
		||||
 | 
			
		||||
	if (timeout == 0)
 | 
			
		||||
	    return -1;
 | 
			
		||||
		return -ETIMEDOUT;
 | 
			
		||||
 | 
			
		||||
	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
 | 
			
		||||
	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_UNCOR_ERROR)
 | 
			
		||||
			return -1;
 | 
			
		||||
			return -EBADMSG;
 | 
			
		||||
 | 
			
		||||
		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)) {
 | 
			
		||||
		pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
		return -EBADMSG;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
		if (err > err_limit) {
 | 
			
		||||
			printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
			return -EBADMSG;
 | 
			
		||||
		} else {
 | 
			
		||||
			ret += err;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
 | 
			
		|||
		}
 | 
			
		||||
	} else if (count < 0) {
 | 
			
		||||
		printk(KERN_ERR "ecc unrecoverable error\n");
 | 
			
		||||
		count = -1;
 | 
			
		||||
		count = -EBADMSG;
 | 
			
		||||
	}
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *buf,
 | 
			
		|||
		return 1;	/* error in ECC data; no action needed */
 | 
			
		||||
 | 
			
		||||
	pr_err("%s: uncorrectable ECC error\n", __func__);
 | 
			
		||||
	return -1;
 | 
			
		||||
	return -EBADMSG;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__nand_correct_data);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -826,12 +826,12 @@ static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */
 | 
			
		|||
	case 1:
 | 
			
		||||
		/* Uncorrectable error */
 | 
			
		||||
		pr_debug("ECC UNCORRECTED_ERROR 1\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
		return -EBADMSG;
 | 
			
		||||
 | 
			
		||||
	case 11:
 | 
			
		||||
		/* UN-Correctable error */
 | 
			
		||||
		pr_debug("ECC UNCORRECTED_ERROR B\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
		return -EBADMSG;
 | 
			
		||||
 | 
			
		||||
	case 12:
 | 
			
		||||
		/* Correctable error */
 | 
			
		||||
| 
						 | 
				
			
			@ -861,7 +861,7 @@ static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */
 | 
			
		|||
				return 0;
 | 
			
		||||
		}
 | 
			
		||||
		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) {
 | 
			
		||||
		dev->dma_error = 0;
 | 
			
		||||
		return -1;
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 */
 | 
			
		||||
		if (ecc_status & R852_ECC_FAIL) {
 | 
			
		||||
			dbg("ecc: unrecoverable error, in half %d", i);
 | 
			
		||||
			error = -1;
 | 
			
		||||
			error = -EBADMSG;
 | 
			
		||||
			goto exit;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -456,7 +456,13 @@ struct nand_hw_control {
 | 
			
		|||
 * @hwctl:	function to control hardware ECC generator. Must only
 | 
			
		||||
 *		be provided if an hardware ECC is available
 | 
			
		||||
 * @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
 | 
			
		||||
 *			should hide the specific layout used by the ECC
 | 
			
		||||
 *			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,
 | 
			
		||||
		      unsigned char *read_ecc, unsigned char *calc_ecc)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
	return -ENOTSUPP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct nand_bch_control *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue