diff options
Diffstat (limited to 'drivers/mtd/nand/raw/nand_base.c')
| -rw-r--r-- | drivers/mtd/nand/raw/nand_base.c | 70 | 
1 files changed, 70 insertions, 0 deletions
| diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index a130320de412..e7b2ba016d8c 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -321,6 +321,9 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)  	if (nand_region_is_secured(chip, ofs, mtd->erasesize))  		return -EIO; +	if (WARN_ONCE(mtd_expert_analysis_mode, mtd_expert_analysis_warning)) +		return 0; +  	if (chip->legacy.block_bad)  		return chip->legacy.block_bad(chip, ofs); @@ -3161,6 +3164,73 @@ static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,  }  /** + * nand_read_page_hwecc_oob_first - Hardware ECC page read with ECC + *                                  data read from OOB area + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read + * + * Hardware ECC for large page chips, which requires the ECC data to be + * extracted from the OOB before the actual data is read. + */ +int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf, +				   int oob_required, int page) +{ +	struct mtd_info *mtd = nand_to_mtd(chip); +	int i, eccsize = chip->ecc.size, ret; +	int eccbytes = chip->ecc.bytes; +	int eccsteps = chip->ecc.steps; +	uint8_t *p = buf; +	uint8_t *ecc_code = chip->ecc.code_buf; +	unsigned int max_bitflips = 0; + +	/* Read the OOB area first */ +	ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); +	if (ret) +		return ret; + +	/* Move read cursor to start of page */ +	ret = nand_change_read_column_op(chip, 0, NULL, 0, false); +	if (ret) +		return ret; + +	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, +					 chip->ecc.total); +	if (ret) +		return ret; + +	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { +		int stat; + +		chip->ecc.hwctl(chip, NAND_ECC_READ); + +		ret = nand_read_data_op(chip, p, eccsize, false, false); +		if (ret) +			return ret; + +		stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL); +		if (stat == -EBADMSG && +		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { +			/* check for empty pages with bitflips */ +			stat = nand_check_erased_ecc_chunk(p, eccsize, +							   &ecc_code[i], +							   eccbytes, NULL, 0, +							   chip->ecc.strength); +		} + +		if (stat < 0) { +			mtd->ecc_stats.failed++; +		} else { +			mtd->ecc_stats.corrected += stat; +			max_bitflips = max_t(unsigned int, max_bitflips, stat); +		} +	} +	return max_bitflips; +} +EXPORT_SYMBOL_GPL(nand_read_page_hwecc_oob_first); + +/**   * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read   * @chip: nand chip info structure   * @buf: buffer to store read data |