mtd: nand: omap: ecc.correct: omap_elm_correct_data: fix erased-page detection for BCHx_HW ECC schemes
As erased-pages do not have ECC stored in their OOB area, so they need to be seperated out from programmed-pages, before doing BCH ECC correction. In current implementation of omap_elm_correct_data() which does ECC correction for BCHx ECC schemes, this erased-pages are detected based on specific marker byte (reserved as 0x00) in ecc-layout. However, this approach has some limitation like; 1) All ecc-scheme layouts do not have such Reserved byte marker to differentiate between erased-page v/s programmed-page. Thus this is a customized solution. 2) Reserved marker byte can itself be subjected to bit-flips causing erased-page to be misunderstood as programmed-page. This patch removes dependency on any marker byte in ecc-layout, instead it compares calc_ecc[] with pattern of ECC-of-all(0xff). This implicitely means that both 'data + oob == all(0xff). Signed-off-by: Pekon Gupta <pekon@ti.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
This commit is contained in:
parent
de0a4d69e6
commit
78f43c5383
@ -1338,21 +1338,8 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
|
|||||||
* @calc_ecc: ecc read from HW ECC registers
|
* @calc_ecc: ecc read from HW ECC registers
|
||||||
*
|
*
|
||||||
* Calculated ecc vector reported as zero in case of non-error pages.
|
* Calculated ecc vector reported as zero in case of non-error pages.
|
||||||
* In case of error/erased pages non-zero error vector is reported.
|
* In case of non-zero ecc vector, first filter out erased-pages, and
|
||||||
* In case of non-zero ecc vector, check read_ecc at fixed offset
|
* then process data via ELM to detect bit-flips.
|
||||||
* (x = 13/7 in case of BCH8/4 == 0) to find page programmed or not.
|
|
||||||
* To handle bit flips in this data, count the number of 0's in
|
|
||||||
* read_ecc[x] and check if it greater than 4. If it is less, it is
|
|
||||||
* programmed page, else erased page.
|
|
||||||
*
|
|
||||||
* 1. If page is erased, check with standard ecc vector (ecc vector
|
|
||||||
* for erased page to find any bit flip). If check fails, bit flip
|
|
||||||
* is present in erased page. Count the bit flips in erased page and
|
|
||||||
* if it falls under correctable level, report page with 0xFF and
|
|
||||||
* update the correctable bit information.
|
|
||||||
* 2. If error is reported on programmed page, update elm error
|
|
||||||
* vector and correct the page with ELM error correction routine.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
||||||
u_char *read_ecc, u_char *calc_ecc)
|
u_char *read_ecc, u_char *calc_ecc)
|
||||||
@ -1367,6 +1354,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
|||||||
u_char *ecc_vec = calc_ecc;
|
u_char *ecc_vec = calc_ecc;
|
||||||
u_char *spare_ecc = read_ecc;
|
u_char *spare_ecc = read_ecc;
|
||||||
u_char *erased_ecc_vec;
|
u_char *erased_ecc_vec;
|
||||||
|
u_char *buf;
|
||||||
|
int bitflip_count;
|
||||||
enum bch_ecc type;
|
enum bch_ecc type;
|
||||||
bool is_error_reported = false;
|
bool is_error_reported = false;
|
||||||
|
|
||||||
@ -1374,10 +1363,12 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
|||||||
case OMAP_ECC_BCH4_CODE_HW:
|
case OMAP_ECC_BCH4_CODE_HW:
|
||||||
/* omit 7th ECC byte reserved for ROM code compatibility */
|
/* omit 7th ECC byte reserved for ROM code compatibility */
|
||||||
actual_eccbytes = ecc->bytes - 1;
|
actual_eccbytes = ecc->bytes - 1;
|
||||||
|
erased_ecc_vec = bch4_vector;
|
||||||
break;
|
break;
|
||||||
case OMAP_ECC_BCH8_CODE_HW:
|
case OMAP_ECC_BCH8_CODE_HW:
|
||||||
/* omit 14th ECC byte reserved for ROM code compatibility */
|
/* omit 14th ECC byte reserved for ROM code compatibility */
|
||||||
actual_eccbytes = ecc->bytes - 1;
|
actual_eccbytes = ecc->bytes - 1;
|
||||||
|
erased_ecc_vec = bch8_vector;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pr_err("invalid driver configuration\n");
|
pr_err("invalid driver configuration\n");
|
||||||
@ -1389,10 +1380,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
|||||||
|
|
||||||
if (info->nand.ecc.strength == BCH8_MAX_ERROR) {
|
if (info->nand.ecc.strength == BCH8_MAX_ERROR) {
|
||||||
type = BCH8_ECC;
|
type = BCH8_ECC;
|
||||||
erased_ecc_vec = bch8_vector;
|
|
||||||
} else {
|
} else {
|
||||||
type = BCH4_ECC;
|
type = BCH4_ECC;
|
||||||
erased_ecc_vec = bch4_vector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < eccsteps ; i++) {
|
for (i = 0; i < eccsteps ; i++) {
|
||||||
@ -1410,44 +1399,36 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (eccflag == 1) {
|
if (eccflag == 1) {
|
||||||
/*
|
if (memcmp(calc_ecc, erased_ecc_vec,
|
||||||
* Set threshold to minimum of 4, half of ecc.strength/2
|
actual_eccbytes) == 0) {
|
||||||
* to allow max bit flip in byte to 4
|
|
||||||
*/
|
|
||||||
unsigned int threshold = min_t(unsigned int, 4,
|
|
||||||
info->nand.ecc.strength / 2);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check data area is programmed by counting
|
|
||||||
* number of 0's at fixed offset in spare area.
|
|
||||||
* Checking count of 0's against threshold.
|
|
||||||
* In case programmed page expects at least threshold
|
|
||||||
* zeros in byte.
|
|
||||||
* If zeros are less than threshold for programmed page/
|
|
||||||
* zeros are more than threshold erased page, either
|
|
||||||
* case page reported as uncorrectable.
|
|
||||||
*/
|
|
||||||
if (hweight8(~read_ecc[actual_eccbytes]) >= threshold) {
|
|
||||||
/*
|
/*
|
||||||
* Update elm error vector as
|
* calc_ecc[] matches pattern for ECC(all 0xff)
|
||||||
* data area is programmed
|
* so this is definitely an erased-page
|
||||||
*/
|
*/
|
||||||
err_vec[i].error_reported = true;
|
|
||||||
is_error_reported = true;
|
|
||||||
} else {
|
} else {
|
||||||
/* Error reported in erased page */
|
buf = &data[info->nand.ecc.size * i];
|
||||||
int bitflip_count;
|
/*
|
||||||
u_char *buf = &data[info->nand.ecc.size * i];
|
* count number of 0-bits in read_buf.
|
||||||
|
* This check can be removed once a similar
|
||||||
if (memcmp(calc_ecc, erased_ecc_vec,
|
* check is introduced in generic NAND driver
|
||||||
actual_eccbytes)) {
|
*/
|
||||||
bitflip_count = erased_sector_bitflips(
|
bitflip_count = erased_sector_bitflips(
|
||||||
buf, read_ecc, info);
|
buf, read_ecc, info);
|
||||||
|
if (bitflip_count) {
|
||||||
if (bitflip_count)
|
/*
|
||||||
stat += bitflip_count;
|
* number of 0-bits within ECC limits
|
||||||
else
|
* So this may be an erased-page
|
||||||
return -EINVAL;
|
*/
|
||||||
|
stat += bitflip_count;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Too many 0-bits. It may be a
|
||||||
|
* - programmed-page, OR
|
||||||
|
* - erased-page with many bit-flips
|
||||||
|
* So this page requires check by ELM
|
||||||
|
*/
|
||||||
|
err_vec[i].error_reported = true;
|
||||||
|
is_error_reported = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user