diff options
| -rw-r--r-- | drivers/mtd/mtdcore.c | 14 | ||||
| -rw-r--r-- | drivers/mtd/mtdpart.c | 12 | ||||
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 18 | ||||
| -rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 3 | ||||
| -rw-r--r-- | include/linux/mtd/nand.h | 3 | 
5 files changed, 38 insertions, 12 deletions
| diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 49c08145a..deda5f244 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -217,11 +217,23 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)  int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,  	     u_char *buf)  { +	int ret_code;  	if (from < 0 || from > mtd->size || len > mtd->size - from)  		return -EINVAL;  	if (!len)  		return 0; -	return mtd->_read(mtd, from, len, retlen, buf); + +	/* +	 * In the absence of an error, drivers return a non-negative integer +	 * representing the maximum number of bitflips that were corrected on +	 * any one ecc region (if applicable; zero otherwise). +	 */ +	ret_code = mtd->_read(mtd, from, len, retlen, buf); +	if (unlikely(ret_code < 0)) +		return ret_code; +	if (mtd->ecc_strength == 0) +		return 0;	/* device lacks ecc */ +	return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;  }  int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 9dfe7bbc9..146ce11eb 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -53,12 +53,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,  	stats = part->master->ecc_stats;  	res = mtd_read(part->master, from + part->offset, len, retlen, buf); -	if (unlikely(res)) { -		if (mtd_is_bitflip(res)) -			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; -		if (mtd_is_eccerr(res)) -			mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed; -	} +	if (unlikely(mtd_is_eccerr(res))) +		mtd->ecc_stats.failed += +			part->master->ecc_stats.failed - stats.failed; +	else +		mtd->ecc_stats.corrected += +			part->master->ecc_stats.corrected - stats.corrected;  	return res;  } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 9e05cef41..d4d586c94 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1238,6 +1238,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  		mtd->oobavail : mtd->oobsize;  	uint8_t *bufpoi, *oob, *buf; +	unsigned int max_bitflips = 0;  	stats = mtd->ecc_stats; @@ -1265,7 +1266,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  			chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); -			/* Now read the page into the buffer */ +			/* +			 * Now read the page into the buffer.  Absent an error, +			 * the read methods return max bitflips per ecc step. +			 */  			if (unlikely(ops->mode == MTD_OPS_RAW))  				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,  							      oob_required, @@ -1284,15 +1288,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  				break;  			} +			max_bitflips = max_t(unsigned int, max_bitflips, ret); +  			/* Transfer not aligned data */  			if (!aligned) {  				if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&  				    !(mtd->ecc_stats.failed - stats.failed) && -				    (ops->mode != MTD_OPS_RAW)) +				    (ops->mode != MTD_OPS_RAW)) {  					chip->pagebuf = realpage; -				else +					chip->pagebuf_bitflips = ret; +				} else {  					/* Invalidate page cache */  					chip->pagebuf = -1; +				}  				memcpy(buf, chip->buffers->databuf + col, bytes);  			} @@ -1310,6 +1318,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  		} else {  			memcpy(buf, chip->buffers->databuf + col, bytes);  			buf += bytes; +			max_bitflips = max_t(unsigned int, max_bitflips, +					     chip->pagebuf_bitflips);  		}  		readlen -= bytes; @@ -1341,7 +1351,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  	if (mtd->ecc_stats.failed - stats.failed)  		return -EBADMSG; -	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +	return max_bitflips;  }  /** diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index ddfe7e7c7..067f8ef18 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -969,7 +969,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  	if (mtd->ecc_stats.failed - stats.failed)  		return -EBADMSG; -	return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +	/* return max bitflips per ecc step; ONENANDs correct 1 bit only */ +	return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;  }  /** diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 205558437..054656559 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -464,6 +464,8 @@ struct nand_buffers {   * @pagemask:		[INTERN] page number mask = number of (pages / chip) - 1   * @pagebuf:		[INTERN] holds the pagenumber which is currently in   *			data_buf. + * @pagebuf_bitflips:	[INTERN] holds the bitflip count for the page which is + *			currently in data_buf.   * @subpagesize:	[INTERN] holds the subpagesize   * @onfi_version:	[INTERN] holds the chip ONFI version (BCD encoded),   *			non 0 if ONFI supported. @@ -531,6 +533,7 @@ struct nand_chip {  	uint64_t chipsize;  	int pagemask;  	int pagebuf; +	unsigned int pagebuf_bitflips;  	int subpagesize;  	uint8_t cellinfo;  	int badblockpos; |