Two main MTD fixes:
1. Read retry counting was off by one, so if we had a true ECC error (i.e., no retry voltage threshold would give a clean read), we would end up returning -EINVAL on the Nth mode instead of -EBADMSG after then (N-1)th mode 2. The OMAP NAND driver had some of its ECC layouts wrong when introduced in 3.13, causing incompatibilities between the bootloader on-flash layout and the layout expected in Linux. The expected layouts are now documented in the commit messages, and we plan to add this under Documentation/mtd/nand/ eventually. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJTDO21AAoJEFySrpd9RFgta5oP/0OKQzrG8BGj7Fok3+OgDWb5 YaO+wGnBbsMjCUECpB55HxcVtDwgzyjjxaZNRcwrKZdkUqM60RqxpcCkU02O92oo 5T1AzE2aB65+eAm4BR3xsgGEG7wMgvMJY+4Fy1PmOvymJi00aTSq/R0Ri0/GEHVh NOxpfazs61x4TX66Fnc6+IL7IupVTprZEjbDxxwIhEOLutmITswBt4M69yYJmTio NtYWY7nTJGq+QWeBfEGFgWYU3yIwHUyo586bpqSpz9l1qkRKk/1VJGbwNUYnM61d 8Vcd8szOHSI0vwU//BBAmTZ7a5KXRtfpD0x0im0HSmGfkBtmyjTU5l5FdZH68SQb ytT8uU53+xwOPpQW+1SipRerKggJQQ62tj6jQ6tAZj0WWerOGPmQhf1c9/KaTawg OXjPF5bIMUVf26vkji68X8VDzpYpP1EqEr4GvTFx223b4wq4XmdusqEW8hakXhwQ XMXKIztbb7SAY4ilYxOljCuGmR79wAJh8h+nOx5Nyw170WtHUyI6WaZjx3NhILOD /GgvFir5CrAwZIg7RyMMmsCXTA9bmsKEzVin69rml9o+XoV5wYucfflpMvm0Gq7A lQi6HSAPVtvZNxcfRFs5p8j6nDNIWwJK/ovIxOzlhs+0KjDDD1yHYdVRoTmPx8Pr kxDUiDpy2FkU8Cb17cRo =qKhw -----END PGP SIGNATURE----- Merge tag 'for-linus-20140225' of git://git.infradead.org/linux-mtd Pull MTD fixes from Brian Norris: "Two main MTD fixes: 1. Read retry counting was off by one, so if we had a true ECC error (i.e., no retry voltage threshold would give a clean read), we would end up returning -EINVAL on the Nth mode instead of -EBADMSG after then (N-1)th mode 2. The OMAP NAND driver had some of its ECC layouts wrong when introduced in 3.13, causing incompatibilities between the bootloader on-flash layout and the layout expected in Linux. The expected layouts are now documented in the commit messages, and we plan to add this under Documentation/mtd/nand/ eventually" * tag 'for-linus-20140225' of git://git.infradead.org/linux-mtd: mtd: nand: omap: fix ecclayout->oobfree->length mtd: nand: omap: fix ecclayout->oobfree->offset mtd: nand: omap: fix ecclayout to be in sync with u-boot NAND driver mtd: nand: fix off-by-one read retry mode counting
This commit is contained in:
commit
e4cc60cbdc
2 changed files with 41 additions and 22 deletions
drivers/mtd/nand
|
@ -1584,7 +1584,7 @@ read_retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mtd->ecc_stats.failed - ecc_failures) {
|
if (mtd->ecc_stats.failed - ecc_failures) {
|
||||||
if (retry_mode + 1 <= chip->read_retries) {
|
if (retry_mode + 1 < chip->read_retries) {
|
||||||
retry_mode++;
|
retry_mode++;
|
||||||
ret = nand_setup_read_retry(mtd,
|
ret = nand_setup_read_retry(mtd,
|
||||||
retry_mode);
|
retry_mode);
|
||||||
|
|
|
@ -1633,6 +1633,7 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||||
int i;
|
int i;
|
||||||
dma_cap_mask_t mask;
|
dma_cap_mask_t mask;
|
||||||
unsigned sig;
|
unsigned sig;
|
||||||
|
unsigned oob_index;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct mtd_part_parser_data ppdata = {};
|
struct mtd_part_parser_data ppdata = {};
|
||||||
|
|
||||||
|
@ -1826,11 +1827,14 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||||
(mtd->writesize /
|
(mtd->writesize /
|
||||||
nand_chip->ecc.size);
|
nand_chip->ecc.size);
|
||||||
if (nand_chip->options & NAND_BUSWIDTH_16)
|
if (nand_chip->options & NAND_BUSWIDTH_16)
|
||||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
oob_index = BADBLOCK_MARKER_LENGTH;
|
||||||
else
|
else
|
||||||
ecclayout->eccpos[0] = 1;
|
oob_index = 1;
|
||||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
|
||||||
ecclayout->eccbytes;
|
ecclayout->eccpos[i] = oob_index;
|
||||||
|
/* no reserved-marker in ecclayout for this ecc-scheme */
|
||||||
|
ecclayout->oobfree->offset =
|
||||||
|
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
|
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
|
||||||
|
@ -1847,9 +1851,15 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||||
(mtd->writesize /
|
(mtd->writesize /
|
||||||
nand_chip->ecc.size);
|
nand_chip->ecc.size);
|
||||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
oob_index = BADBLOCK_MARKER_LENGTH;
|
||||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
|
||||||
ecclayout->eccbytes;
|
ecclayout->eccpos[i] = oob_index;
|
||||||
|
if (((i + 1) % nand_chip->ecc.bytes) == 0)
|
||||||
|
oob_index++;
|
||||||
|
}
|
||||||
|
/* include reserved-marker in ecclayout->oobfree calculation */
|
||||||
|
ecclayout->oobfree->offset = 1 +
|
||||||
|
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
|
||||||
/* software bch library is used for locating errors */
|
/* software bch library is used for locating errors */
|
||||||
nand_chip->ecc.priv = nand_bch_init(mtd,
|
nand_chip->ecc.priv = nand_bch_init(mtd,
|
||||||
nand_chip->ecc.size,
|
nand_chip->ecc.size,
|
||||||
|
@ -1883,9 +1893,12 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||||
(mtd->writesize /
|
(mtd->writesize /
|
||||||
nand_chip->ecc.size);
|
nand_chip->ecc.size);
|
||||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
oob_index = BADBLOCK_MARKER_LENGTH;
|
||||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
|
||||||
ecclayout->eccbytes;
|
ecclayout->eccpos[i] = oob_index;
|
||||||
|
/* reserved marker already included in ecclayout->eccbytes */
|
||||||
|
ecclayout->oobfree->offset =
|
||||||
|
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
|
||||||
/* This ECC scheme requires ELM H/W block */
|
/* This ECC scheme requires ELM H/W block */
|
||||||
if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
|
if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
|
||||||
pr_err("nand: error: could not initialize ELM\n");
|
pr_err("nand: error: could not initialize ELM\n");
|
||||||
|
@ -1913,9 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||||
(mtd->writesize /
|
(mtd->writesize /
|
||||||
nand_chip->ecc.size);
|
nand_chip->ecc.size);
|
||||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
oob_index = BADBLOCK_MARKER_LENGTH;
|
||||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
|
||||||
ecclayout->eccbytes;
|
ecclayout->eccpos[i] = oob_index;
|
||||||
|
if (((i + 1) % nand_chip->ecc.bytes) == 0)
|
||||||
|
oob_index++;
|
||||||
|
}
|
||||||
|
/* include reserved-marker in ecclayout->oobfree calculation */
|
||||||
|
ecclayout->oobfree->offset = 1 +
|
||||||
|
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
|
||||||
/* software bch library is used for locating errors */
|
/* software bch library is used for locating errors */
|
||||||
nand_chip->ecc.priv = nand_bch_init(mtd,
|
nand_chip->ecc.priv = nand_bch_init(mtd,
|
||||||
nand_chip->ecc.size,
|
nand_chip->ecc.size,
|
||||||
|
@ -1956,9 +1975,12 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||||
(mtd->writesize /
|
(mtd->writesize /
|
||||||
nand_chip->ecc.size);
|
nand_chip->ecc.size);
|
||||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
oob_index = BADBLOCK_MARKER_LENGTH;
|
||||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
|
||||||
ecclayout->eccbytes;
|
ecclayout->eccpos[i] = oob_index;
|
||||||
|
/* reserved marker already included in ecclayout->eccbytes */
|
||||||
|
ecclayout->oobfree->offset =
|
||||||
|
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
|
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
|
||||||
|
@ -1972,11 +1994,8 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||||
goto return_error;
|
goto return_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* populate remaining ECC layout data */
|
/* all OOB bytes from oobfree->offset till end off OOB are free */
|
||||||
ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH +
|
ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
|
||||||
ecclayout->eccbytes);
|
|
||||||
for (i = 1; i < ecclayout->eccbytes; i++)
|
|
||||||
ecclayout->eccpos[i] = ecclayout->eccpos[0] + i;
|
|
||||||
/* check if NAND device's OOB is enough to store ECC signatures */
|
/* check if NAND device's OOB is enough to store ECC signatures */
|
||||||
if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
|
if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
|
||||||
pr_err("not enough OOB bytes required = %d, available=%d\n",
|
pr_err("not enough OOB bytes required = %d, available=%d\n",
|
||||||
|
|
Loading…
Add table
Reference in a new issue