mtd: nand: use nand_check_erased_ecc_chunk in default ECC read functions
The default NAND read functions are relying on the underlying controller driver to correct bitflips, but some of those controllers cannot properly fix bitflips in erased pages. Check for bitflips in erased pages in default core functions if the driver delegated the this check by setting the NAND_ECC_GENERIC_ERASED_CHECK flag. 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
6e9411923b
commit
40cbe6eee9
|
@ -1426,6 +1426,16 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
|
|
||||||
stat = chip->ecc.correct(mtd, p,
|
stat = chip->ecc.correct(mtd, p,
|
||||||
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
||||||
|
if (stat == -EBADMSG &&
|
||||||
|
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||||
|
/* check for empty pages with bitflips */
|
||||||
|
stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
|
||||||
|
&chip->buffers->ecccode[i],
|
||||||
|
chip->ecc.bytes,
|
||||||
|
NULL, 0,
|
||||||
|
chip->ecc.strength);
|
||||||
|
}
|
||||||
|
|
||||||
if (stat < 0) {
|
if (stat < 0) {
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1475,6 +1485,15 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
int stat;
|
int stat;
|
||||||
|
|
||||||
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||||
|
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) {
|
if (stat < 0) {
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1527,6 +1546,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
|
||||||
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||||
|
|
||||||
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
|
stat = chip->ecc.correct(mtd, 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) {
|
if (stat < 0) {
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1554,6 +1582,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
int i, eccsize = chip->ecc.size;
|
int i, eccsize = chip->ecc.size;
|
||||||
int eccbytes = chip->ecc.bytes;
|
int eccbytes = chip->ecc.bytes;
|
||||||
int eccsteps = chip->ecc.steps;
|
int eccsteps = chip->ecc.steps;
|
||||||
|
int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
|
||||||
uint8_t *p = buf;
|
uint8_t *p = buf;
|
||||||
uint8_t *oob = chip->oob_poi;
|
uint8_t *oob = chip->oob_poi;
|
||||||
unsigned int max_bitflips = 0;
|
unsigned int max_bitflips = 0;
|
||||||
|
@ -1573,19 +1602,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
chip->read_buf(mtd, oob, eccbytes);
|
chip->read_buf(mtd, oob, eccbytes);
|
||||||
stat = chip->ecc.correct(mtd, p, oob, NULL);
|
stat = chip->ecc.correct(mtd, p, oob, NULL);
|
||||||
|
|
||||||
if (stat < 0) {
|
|
||||||
mtd->ecc_stats.failed++;
|
|
||||||
} else {
|
|
||||||
mtd->ecc_stats.corrected += stat;
|
|
||||||
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
oob += eccbytes;
|
oob += eccbytes;
|
||||||
|
|
||||||
if (chip->ecc.postpad) {
|
if (chip->ecc.postpad) {
|
||||||
chip->read_buf(mtd, oob, chip->ecc.postpad);
|
chip->read_buf(mtd, oob, chip->ecc.postpad);
|
||||||
oob += chip->ecc.postpad;
|
oob += chip->ecc.postpad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stat == -EBADMSG &&
|
||||||
|
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||||
|
/* check for empty pages with bitflips */
|
||||||
|
stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
|
||||||
|
oob - eccpadbytes,
|
||||||
|
eccpadbytes,
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate remaining oob bytes */
|
/* Calculate remaining oob bytes */
|
||||||
|
|
|
@ -129,6 +129,14 @@ typedef enum {
|
||||||
/* Enable Hardware ECC before syndrome is read back from flash */
|
/* Enable Hardware ECC before syndrome is read back from flash */
|
||||||
#define NAND_ECC_READSYN 2
|
#define NAND_ECC_READSYN 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable generic NAND 'page erased' check. This check is only done when
|
||||||
|
* ecc.correct() returns -EBADMSG.
|
||||||
|
* Set this flag if your implementation does not fix bitflips in erased
|
||||||
|
* pages and you want to rely on the default implementation.
|
||||||
|
*/
|
||||||
|
#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0)
|
||||||
|
|
||||||
/* Bit mask for flags passed to do_nand_read_ecc */
|
/* Bit mask for flags passed to do_nand_read_ecc */
|
||||||
#define NAND_GET_DEVICE 0x80
|
#define NAND_GET_DEVICE 0x80
|
||||||
|
|
||||||
|
@ -451,6 +459,7 @@ struct nand_hw_control {
|
||||||
* @total: total number of ECC bytes per page
|
* @total: total number of ECC bytes per page
|
||||||
* @prepad: padding information for syndrome based ECC generators
|
* @prepad: padding information for syndrome based ECC generators
|
||||||
* @postpad: padding information for syndrome based ECC generators
|
* @postpad: padding information for syndrome based ECC generators
|
||||||
|
* @options: ECC specific options (see NAND_ECC_XXX flags defined above)
|
||||||
* @layout: ECC layout control struct pointer
|
* @layout: ECC layout control struct pointer
|
||||||
* @priv: pointer to private ECC control data
|
* @priv: pointer to private ECC control data
|
||||||
* @hwctl: function to control hardware ECC generator. Must only
|
* @hwctl: function to control hardware ECC generator. Must only
|
||||||
|
@ -500,6 +509,7 @@ struct nand_ecc_ctrl {
|
||||||
int strength;
|
int strength;
|
||||||
int prepad;
|
int prepad;
|
||||||
int postpad;
|
int postpad;
|
||||||
|
unsigned int options;
|
||||||
struct nand_ecclayout *layout;
|
struct nand_ecclayout *layout;
|
||||||
void *priv;
|
void *priv;
|
||||||
void (*hwctl)(struct mtd_info *mtd, int mode);
|
void (*hwctl)(struct mtd_info *mtd, int mode);
|
||||||
|
|
Loading…
Reference in a new issue