diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-25 16:16:05 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-25 16:16:05 -0500 |
| commit | e4cc60cbdc4fd1d1050824937079bed2a4108864 (patch) | |
| tree | edda38c0244d05363b9d55b99b968171bf5da37e | |
| parent | c378a6566392789dd7400b13e4d4064cbbb9a087 (diff) | |
| parent | bb38eefb6858ce16b34716145b9597a5680aa54c (diff) | |
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
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 2 | ||||
| -rw-r--r-- | drivers/mtd/nand/omap2.c | 61 |
2 files changed, 41 insertions, 22 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 59eba5d2c685..9715a7ba164a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
| @@ -1584,7 +1584,7 @@ read_retry: | |||
| 1584 | } | 1584 | } |
| 1585 | 1585 | ||
| 1586 | if (mtd->ecc_stats.failed - ecc_failures) { | 1586 | if (mtd->ecc_stats.failed - ecc_failures) { |
| 1587 | if (retry_mode + 1 <= chip->read_retries) { | 1587 | if (retry_mode + 1 < chip->read_retries) { |
| 1588 | retry_mode++; | 1588 | retry_mode++; |
| 1589 | ret = nand_setup_read_retry(mtd, | 1589 | ret = nand_setup_read_retry(mtd, |
| 1590 | retry_mode); | 1590 | retry_mode); |
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index ef4190a02b7b..bf642ceef681 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
| @@ -1633,6 +1633,7 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
| 1633 | int i; | 1633 | int i; |
| 1634 | dma_cap_mask_t mask; | 1634 | dma_cap_mask_t mask; |
| 1635 | unsigned sig; | 1635 | unsigned sig; |
| 1636 | unsigned oob_index; | ||
| 1636 | struct resource *res; | 1637 | struct resource *res; |
| 1637 | struct mtd_part_parser_data ppdata = {}; | 1638 | struct mtd_part_parser_data ppdata = {}; |
| 1638 | 1639 | ||
| @@ -1826,11 +1827,14 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
| 1826 | (mtd->writesize / | 1827 | (mtd->writesize / |
| 1827 | nand_chip->ecc.size); | 1828 | nand_chip->ecc.size); |
| 1828 | if (nand_chip->options & NAND_BUSWIDTH_16) | 1829 | if (nand_chip->options & NAND_BUSWIDTH_16) |
| 1829 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | 1830 | oob_index = BADBLOCK_MARKER_LENGTH; |
| 1830 | else | 1831 | else |
| 1831 | ecclayout->eccpos[0] = 1; | 1832 | oob_index = 1; |
| 1832 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + | 1833 | for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) |
| 1833 | ecclayout->eccbytes; | 1834 | ecclayout->eccpos[i] = oob_index; |
| 1835 | /* no reserved-marker in ecclayout for this ecc-scheme */ | ||
| 1836 | ecclayout->oobfree->offset = | ||
| 1837 | ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; | ||
| 1834 | break; | 1838 | break; |
| 1835 | 1839 | ||
| 1836 | case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: | 1840 | case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: |
| @@ -1847,9 +1851,15 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
| 1847 | ecclayout->eccbytes = nand_chip->ecc.bytes * | 1851 | ecclayout->eccbytes = nand_chip->ecc.bytes * |
| 1848 | (mtd->writesize / | 1852 | (mtd->writesize / |
| 1849 | nand_chip->ecc.size); | 1853 | nand_chip->ecc.size); |
| 1850 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | 1854 | oob_index = BADBLOCK_MARKER_LENGTH; |
| 1851 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + | 1855 | for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) { |
| 1852 | ecclayout->eccbytes; | 1856 | ecclayout->eccpos[i] = oob_index; |
| 1857 | if (((i + 1) % nand_chip->ecc.bytes) == 0) | ||
| 1858 | oob_index++; | ||
| 1859 | } | ||
| 1860 | /* include reserved-marker in ecclayout->oobfree calculation */ | ||
| 1861 | ecclayout->oobfree->offset = 1 + | ||
| 1862 | ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; | ||
| 1853 | /* software bch library is used for locating errors */ | 1863 | /* software bch library is used for locating errors */ |
| 1854 | nand_chip->ecc.priv = nand_bch_init(mtd, | 1864 | nand_chip->ecc.priv = nand_bch_init(mtd, |
| 1855 | nand_chip->ecc.size, | 1865 | nand_chip->ecc.size, |
| @@ -1883,9 +1893,12 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
| 1883 | ecclayout->eccbytes = nand_chip->ecc.bytes * | 1893 | ecclayout->eccbytes = nand_chip->ecc.bytes * |
| 1884 | (mtd->writesize / | 1894 | (mtd->writesize / |
| 1885 | nand_chip->ecc.size); | 1895 | nand_chip->ecc.size); |
| 1886 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | 1896 | oob_index = BADBLOCK_MARKER_LENGTH; |
| 1887 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + | 1897 | for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) |
| 1888 | ecclayout->eccbytes; | 1898 | ecclayout->eccpos[i] = oob_index; |
| 1899 | /* reserved marker already included in ecclayout->eccbytes */ | ||
| 1900 | ecclayout->oobfree->offset = | ||
| 1901 | ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; | ||
| 1889 | /* This ECC scheme requires ELM H/W block */ | 1902 | /* This ECC scheme requires ELM H/W block */ |
| 1890 | if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { | 1903 | if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { |
| 1891 | pr_err("nand: error: could not initialize ELM\n"); | 1904 | pr_err("nand: error: could not initialize ELM\n"); |
| @@ -1913,9 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
| 1913 | ecclayout->eccbytes = nand_chip->ecc.bytes * | 1926 | ecclayout->eccbytes = nand_chip->ecc.bytes * |
| 1914 | (mtd->writesize / | 1927 | (mtd->writesize / |
| 1915 | nand_chip->ecc.size); | 1928 | nand_chip->ecc.size); |
| 1916 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | 1929 | oob_index = BADBLOCK_MARKER_LENGTH; |
| 1917 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + | 1930 | for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) { |
| 1918 | ecclayout->eccbytes; | 1931 | ecclayout->eccpos[i] = oob_index; |
| 1932 | if (((i + 1) % nand_chip->ecc.bytes) == 0) | ||
| 1933 | oob_index++; | ||
| 1934 | } | ||
| 1935 | /* include reserved-marker in ecclayout->oobfree calculation */ | ||
| 1936 | ecclayout->oobfree->offset = 1 + | ||
| 1937 | ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; | ||
| 1919 | /* software bch library is used for locating errors */ | 1938 | /* software bch library is used for locating errors */ |
| 1920 | nand_chip->ecc.priv = nand_bch_init(mtd, | 1939 | nand_chip->ecc.priv = nand_bch_init(mtd, |
| 1921 | nand_chip->ecc.size, | 1940 | nand_chip->ecc.size, |
| @@ -1956,9 +1975,12 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
| 1956 | ecclayout->eccbytes = nand_chip->ecc.bytes * | 1975 | ecclayout->eccbytes = nand_chip->ecc.bytes * |
| 1957 | (mtd->writesize / | 1976 | (mtd->writesize / |
| 1958 | nand_chip->ecc.size); | 1977 | nand_chip->ecc.size); |
| 1959 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | 1978 | oob_index = BADBLOCK_MARKER_LENGTH; |
| 1960 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + | 1979 | for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) |
| 1961 | ecclayout->eccbytes; | 1980 | ecclayout->eccpos[i] = oob_index; |
| 1981 | /* reserved marker already included in ecclayout->eccbytes */ | ||
| 1982 | ecclayout->oobfree->offset = | ||
| 1983 | ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; | ||
| 1962 | break; | 1984 | break; |
| 1963 | #else | 1985 | #else |
| 1964 | pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); | 1986 | 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 | goto return_error; | 1994 | goto return_error; |
| 1973 | } | 1995 | } |
| 1974 | 1996 | ||
| 1975 | /* populate remaining ECC layout data */ | 1997 | /* all OOB bytes from oobfree->offset till end off OOB are free */ |
| 1976 | ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH + | 1998 | ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; |
| 1977 | ecclayout->eccbytes); | ||
| 1978 | for (i = 1; i < ecclayout->eccbytes; i++) | ||
| 1979 | ecclayout->eccpos[i] = ecclayout->eccpos[0] + i; | ||
| 1980 | /* check if NAND device's OOB is enough to store ECC signatures */ | 1999 | /* check if NAND device's OOB is enough to store ECC signatures */ |
| 1981 | if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { | 2000 | if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { |
| 1982 | pr_err("not enough OOB bytes required = %d, available=%d\n", | 2001 | pr_err("not enough OOB bytes required = %d, available=%d\n", |
