Commit e4cc60cb authored by Linus Torvalds's avatar Linus Torvalds

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
parents c378a656 bb38eefb
...@@ -1584,7 +1584,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, ...@@ -1584,7 +1584,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
} }
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment