2015-12-07 22:26:48

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 00/23] mtd: rework ECC layout definition

Hello,

This patchset aims at getting rid of the nand_ecclayout limitations.
struct nand_ecclayout is defining fixed eccpos and oobfree arrays which
can only be increased by modifying the MTD_MAX_ECCPOS_ENTRIES_LARGE and
MTD_MAX_OOBFREE_ENTRIES_LARGE macros.
This approach forces us to modify the macro values each time we add a
new NAND chip with a bigger OOB area, and increasing these arrays also
penalize all platforms, even those who only support small NAND devices
(with small OOB area).

The idea to overcome this limitation, is to define the ECC/OOB layout
by the mean of two functions: ->eccpos() and ->oobfree(), which will
basically return the same information has those stored in the
nand_ecclayout struct.

Another advantage of this solution is that ECC layouts are usually
following a repetitive pattern (i.e. leave X bytes free and put Y bytes
of ECC per ECC chunk), which allows one to implement the ->eccpos()
and ->oobfree() functions with a simple logic that can be applied
to any size of OOB.

Patches 1 to 10 are just cleanups or trivial fixes that can be taken
independently.

Patch 19 is just an aggregate of several smaller commits (one per
driver), and has been submitted this way to limit the size of the
series. If everybody agrees on this approach, I'll resubmit the series
will those changes separated in different commits (as done here [1]).

Also note that the last two commits are removing the nand_ecclayout
definition, thus preventing any new driver to use this structure.
Of course, this step can be delayed if some of the previous patches
are not accepted.

Best Regards,

Boris

[1]https://github.com/bbrezillon/linux-sunxi/commits/nand/ecclayout2

Boris Brezillon (23):
mtd: kill the ecclayout->oobavail field
mtd: inftl: kill unused oobinfo field
mtd: nftl: kill unused oobinfo field
mtd: nand: s3c2410: kill the ->ecc_layout field
mtd: nand: jz4770: kill the ->ecc_layout field
mtd: nand: kill unused ->ecclayout field in platform_nand_chip struct
staging: mt29f_spinand: kill unused ecclayout field
mtd: nand: lpc32xx_mlc: fix ecc.size
mtd: nand: vf610: remove useless mtd->ecclayout assignment
mtd: nand: simplify nand_bch_init() usage
mtd: add mtd_eccpos(), mtd_oobfree() and mtd_eccbytes() helper
functions
mtd: use mtd_eccpos() and mtd_oobfree() where appropriate
mtd: add mtd_set_ecclayout() helper function
mtd: use mtd_set_ecclayout() where appropriate
mtd: create an mtd_ooblayout_ops struct to ease ECC layout definition
mtd: docg3: switch to mtd_ooblayout_ops
mtd: nand: implement the default mtd_ooblayout_ops
mtd: nand: bch: switch to nand_ecclayout_pos
mtd: nand: switch all drivers to mtd_ooblayout_ops
mtd: onenand: switch to mtd_ooblayout_ops
staging: mt29f_spinand: switch to mtd_ooblayout_ops
mtd: nand: kill layout field
mtd: kill the nand_ecclayout struct

arch/arm/mach-pxa/spitz.c | 41 +++-
arch/arm/plat-samsung/devs.c | 9 -
arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 4 +-
arch/mips/jz4740/board-qi_lb60.c | 83 ++++---
drivers/mtd/devices/docg3.c | 39 +++-
drivers/mtd/mtdchar.c | 95 +++++---
drivers/mtd/mtdconcat.c | 2 +-
drivers/mtd/mtdpart.c | 22 +-
drivers/mtd/mtdswap.c | 20 +-
drivers/mtd/nand/atmel_nand.c | 100 ++++----
drivers/mtd/nand/bf5xx_nand.c | 47 ++--
drivers/mtd/nand/brcmnand/brcmnand.c | 258 ++++++++++++---------
drivers/mtd/nand/cafe_nand.c | 42 +++-
drivers/mtd/nand/davinci_nand.c | 114 ++++-----
drivers/mtd/nand/denali.c | 48 ++--
drivers/mtd/nand/diskonchip.c | 34 ++-
drivers/mtd/nand/docg4.c | 30 ++-
drivers/mtd/nand/fsl_elbc_nand.c | 79 ++++---
drivers/mtd/nand/fsl_ifc_nand.c | 226 +++++-------------
drivers/mtd/nand/fsmc_nand.c | 294 +++++++-----------------
drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 57 +++--
drivers/mtd/nand/hisi504_nand.c | 27 ++-
drivers/mtd/nand/jz4740_nand.c | 5 +-
drivers/mtd/nand/lpc32xx_mlc.c | 51 ++--
drivers/mtd/nand/lpc32xx_slc.c | 41 +++-
drivers/mtd/nand/mxc_nand.c | 206 ++++++++---------
drivers/mtd/nand/nand_base.c | 229 ++++++++++--------
drivers/mtd/nand/nand_bch.c | 45 ++--
drivers/mtd/nand/omap2.c | 219 ++++++++++--------
drivers/mtd/nand/plat_nand.c | 1 -
drivers/mtd/nand/pxa3xx_nand.c | 101 ++++----
drivers/mtd/nand/s3c2410.c | 31 ++-
drivers/mtd/nand/sh_flctl.c | 80 +++++--
drivers/mtd/nand/sharpsl.c | 2 +-
drivers/mtd/nand/sm_common.c | 88 +++++--
drivers/mtd/nand/sunxi_nand.c | 112 ++++-----
drivers/mtd/nand/vf610_nfc.c | 36 +--
drivers/mtd/onenand/onenand_base.c | 221 ++++++++++--------
drivers/mtd/tests/oobtest.c | 49 ++--
drivers/staging/mt29f_spinand/mt29f_spinand.c | 45 ++--
drivers/staging/mt29f_spinand/mt29f_spinand.h | 1 -
fs/jffs2/wbuf.c | 6 +-
include/linux/mtd/inftl.h | 1 -
include/linux/mtd/mtd.h | 60 ++++-
include/linux/mtd/nand.h | 6 +-
include/linux/mtd/nand_bch.h | 8 +-
include/linux/mtd/nftl.h | 1 -
include/linux/mtd/onenand.h | 2 -
include/linux/mtd/sharpsl.h | 2 +-
include/linux/platform_data/mtd-nand-s3c2410.h | 1 -
include/uapi/mtd/mtd-abi.h | 2 +-
51 files changed, 1763 insertions(+), 1560 deletions(-)

--
2.1.4


2015-12-07 22:26:51

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 01/23] mtd: kill the ecclayout->oobavail field

ecclayout->oobavail is just redundant with the mtd->oobavail field.
Moreover, it prevents static const definition of ecc layouts since the
NAND framework is calculating this value based on the ecclayout->oobfree
field.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/devices/docg3.c | 5 ++-
drivers/mtd/mtdswap.c | 16 ++++-----
drivers/mtd/nand/brcmnand/brcmnand.c | 3 --
drivers/mtd/nand/docg4.c | 1 -
drivers/mtd/nand/hisi504_nand.c | 1 -
drivers/mtd/nand/nand_base.c | 12 +++----
drivers/mtd/onenand/onenand_base.c | 16 ++++-----
drivers/mtd/tests/oobtest.c | 49 +++++++++++++--------------
drivers/staging/mt29f_spinand/mt29f_spinand.c | 1 -
fs/jffs2/wbuf.c | 6 ++--
include/linux/mtd/mtd.h | 1 -
11 files changed, 48 insertions(+), 63 deletions(-)

diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index c3a2695..e7b2e43 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -72,13 +72,11 @@ MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, "
* @eccbytes: 8 bytes are used (1 for Hamming ECC, 7 for BCH ECC)
* @eccpos: ecc positions (byte 7 is Hamming ECC, byte 8-14 are BCH ECC)
* @oobfree: free pageinfo bytes (byte 0 until byte 6, byte 15
- * @oobavail: 8 available bytes remaining after ECC toll
*/
static struct nand_ecclayout docg3_oobinfo = {
.eccbytes = 8,
.eccpos = {7, 8, 9, 10, 11, 12, 13, 14},
.oobfree = {{0, 7}, {15, 1} },
- .oobavail = 8,
};

static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
@@ -1438,7 +1436,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
oobdelta = mtd->oobsize;
break;
case MTD_OPS_AUTO_OOB:
- oobdelta = mtd->ecclayout->oobavail;
+ oobdelta = mtd->oobavail;
break;
default:
return -EINVAL;
@@ -1860,6 +1858,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
mtd->_write_oob = doc_write_oob;
mtd->_block_isbad = doc_block_isbad;
mtd->ecclayout = &docg3_oobinfo;
+ mtd->oobavail = 8;
mtd->ecc_strength = DOC_ECC_BCH_T;

return 0;
diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index fc8b3d1..d330eb1 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -346,7 +346,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
if (mtd_can_have_bb(d->mtd) && mtd_block_isbad(d->mtd, offset))
return MTDSWAP_SCANNED_BAD;

- ops.ooblen = 2 * d->mtd->ecclayout->oobavail;
+ ops.ooblen = 2 * d->mtd->oobavail;
ops.oobbuf = d->oob_buf;
ops.ooboffs = 0;
ops.datbuf = NULL;
@@ -359,7 +359,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)

data = (struct mtdswap_oobdata *)d->oob_buf;
data2 = (struct mtdswap_oobdata *)
- (d->oob_buf + d->mtd->ecclayout->oobavail);
+ (d->oob_buf + d->mtd->oobavail);

if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) {
eb->erase_count = le32_to_cpu(data->count);
@@ -933,7 +933,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,

ops.mode = MTD_OPS_AUTO_OOB;
ops.len = mtd->writesize;
- ops.ooblen = mtd->ecclayout->oobavail;
+ ops.ooblen = mtd->oobavail;
ops.ooboffs = 0;
ops.datbuf = d->page_buf;
ops.oobbuf = d->oob_buf;
@@ -945,7 +945,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,
for (i = 0; i < mtd_pages; i++) {
patt = mtdswap_test_patt(test + i);
memset(d->page_buf, patt, mtd->writesize);
- memset(d->oob_buf, patt, mtd->ecclayout->oobavail);
+ memset(d->oob_buf, patt, mtd->oobavail);
ret = mtd_write_oob(mtd, pos, &ops);
if (ret)
goto error;
@@ -964,7 +964,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,
if (p1[j] != patt)
goto error;

- for (j = 0; j < mtd->ecclayout->oobavail; j++)
+ for (j = 0; j < mtd->oobavail; j++)
if (p2[j] != (unsigned char)patt)
goto error;

@@ -1387,7 +1387,7 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks,
if (!d->page_buf)
goto page_buf_fail;

- d->oob_buf = kmalloc(2 * mtd->ecclayout->oobavail, GFP_KERNEL);
+ d->oob_buf = kmalloc(2 * mtd->oobavail, GFP_KERNEL);
if (!d->oob_buf)
goto oob_buf_fail;

@@ -1454,10 +1454,10 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
return;
}

- if (!mtd->oobsize || oinfo->oobavail < MTDSWAP_OOBSIZE) {
+ if (!mtd->oobsize || mtd->oobavail < MTDSWAP_OOBSIZE) {
printk(KERN_ERR "%s: Not enough free bytes in OOB, "
"%d available, %zu needed.\n",
- MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE);
+ MTDSWAP_PREFIX, mtd->oobavail, MTDSWAP_OOBSIZE);
return;
}

diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index 35d78f7..a906ec2 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -845,9 +845,6 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
break;
}
out:
- /* Sum available OOB */
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE; i++)
- layout->oobavail += layout->oobfree[i].length;
return layout;
}

diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index 408cf69..fdce91a 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -225,7 +225,6 @@ struct docg4_priv {
static struct nand_ecclayout docg4_oobinfo = {
.eccbytes = 9,
.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
- .oobavail = 5,
.oobfree = { {.offset = 2, .length = 5} }
};

diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
index 0aad4ac..32a5a4c 100644
--- a/drivers/mtd/nand/hisi504_nand.c
+++ b/drivers/mtd/nand/hisi504_nand.c
@@ -633,7 +633,6 @@ static void hisi_nfc_host_init(struct hinfc_host *host)
}

static struct nand_ecclayout nand_ecc_2K_16bits = {
- .oobavail = 6,
.oobfree = { {2, 6} },
};

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0748a13..1107f5c1 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2037,7 +2037,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
stats = mtd->ecc_stats;

if (ops->mode == MTD_OPS_AUTO_OOB)
- len = chip->ecc.layout->oobavail;
+ len = mtd->oobavail;
else
len = mtd->oobsize;

@@ -2728,7 +2728,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
__func__, (unsigned int)to, (int)ops->ooblen);

if (ops->mode == MTD_OPS_AUTO_OOB)
- len = chip->ecc.layout->oobavail;
+ len = mtd->oobavail;
else
len = mtd->oobsize;

@@ -4285,11 +4285,9 @@ int nand_scan_tail(struct mtd_info *mtd)
* The number of bytes available for a client to place data into
* the out of band area.
*/
- ecc->layout->oobavail = 0;
- for (i = 0; ecc->layout->oobfree[i].length
- && i < ARRAY_SIZE(ecc->layout->oobfree); i++)
- ecc->layout->oobavail += ecc->layout->oobfree[i].length;
- mtd->oobavail = ecc->layout->oobavail;
+ mtd->oobavail = 0;
+ for (i = 0; ecc->layout->oobfree[i].length; i++)
+ mtd->oobavail += ecc->layout->oobfree[i].length;

/* ECC sanity check: warn if it's too weak */
if (!nand_ecc_strength_good(mtd))
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 43b3392..d70bbfd 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1125,7 +1125,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
(int)len);

if (ops->mode == MTD_OPS_AUTO_OOB)
- oobsize = this->ecclayout->oobavail;
+ oobsize = mtd->oobavail;
else
oobsize = mtd->oobsize;

@@ -1230,7 +1230,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
(int)len);

if (ops->mode == MTD_OPS_AUTO_OOB)
- oobsize = this->ecclayout->oobavail;
+ oobsize = mtd->oobavail;
else
oobsize = mtd->oobsize;

@@ -1365,7 +1365,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
ops->oobretlen = 0;

if (mode == MTD_OPS_AUTO_OOB)
- oobsize = this->ecclayout->oobavail;
+ oobsize = mtd->oobavail;
else
oobsize = mtd->oobsize;

@@ -1887,7 +1887,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
return 0;

if (ops->mode == MTD_OPS_AUTO_OOB)
- oobsize = this->ecclayout->oobavail;
+ oobsize = mtd->oobavail;
else
oobsize = mtd->oobsize;

@@ -2063,7 +2063,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
ops->oobretlen = 0;

if (mode == MTD_OPS_AUTO_OOB)
- oobsize = this->ecclayout->oobavail;
+ oobsize = mtd->oobavail;
else
oobsize = mtd->oobsize;

@@ -4049,12 +4049,10 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
* The number of bytes available for a client to place data into
* the out of band area
*/
- this->ecclayout->oobavail = 0;
+ mtd->oobavail = 0;
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
this->ecclayout->oobfree[i].length; i++)
- this->ecclayout->oobavail +=
- this->ecclayout->oobfree[i].length;
- mtd->oobavail = this->ecclayout->oobavail;
+ mtd->oobavail += this->ecclayout->oobfree[i].length;

mtd->ecclayout = this->ecclayout;
mtd->ecc_strength = 1;
diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c
index 3176212..1cb3f77 100644
--- a/drivers/mtd/tests/oobtest.c
+++ b/drivers/mtd/tests/oobtest.c
@@ -215,19 +215,19 @@ static int verify_eraseblock(int ebnum)
pr_info("ignoring error as within bitflip_limit\n");
}

- if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
+ if (use_offset != 0 || use_len < mtd->oobavail) {
int k;

ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
- ops.ooblen = mtd->ecclayout->oobavail;
+ ops.ooblen = mtd->oobavail;
ops.oobretlen = 0;
ops.ooboffs = 0;
ops.datbuf = NULL;
ops.oobbuf = readbuf;
err = mtd_read_oob(mtd, addr, &ops);
- if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
+ if (err || ops.oobretlen != mtd->oobavail) {
pr_err("error: readoob failed at %#llx\n",
(long long)addr);
errcnt += 1;
@@ -244,7 +244,7 @@ static int verify_eraseblock(int ebnum)
/* verify post-(use_offset + use_len) area for 0xff */
k = use_offset + use_len;
bitflips += memffshow(addr, k, readbuf + k,
- mtd->ecclayout->oobavail - k);
+ mtd->oobavail - k);

if (bitflips > bitflip_limit) {
pr_err("error: verify failed at %#llx\n",
@@ -269,8 +269,8 @@ static int verify_eraseblock_in_one_go(int ebnum)
struct mtd_oob_ops ops;
int err = 0;
loff_t addr = (loff_t)ebnum * mtd->erasesize;
- size_t len = mtd->ecclayout->oobavail * pgcnt;
- size_t oobavail = mtd->ecclayout->oobavail;
+ size_t len = mtd->oobavail * pgcnt;
+ size_t oobavail = mtd->oobavail;
size_t bitflips;
int i;

@@ -394,8 +394,8 @@ static int __init mtd_oobtest_init(void)
goto out;

use_offset = 0;
- use_len = mtd->ecclayout->oobavail;
- use_len_max = mtd->ecclayout->oobavail;
+ use_len = mtd->oobavail;
+ use_len_max = mtd->oobavail;
vary_offset = 0;

/* First test: write all OOB, read it back and verify */
@@ -460,8 +460,8 @@ static int __init mtd_oobtest_init(void)

/* Write all eraseblocks */
use_offset = 0;
- use_len = mtd->ecclayout->oobavail;
- use_len_max = mtd->ecclayout->oobavail;
+ use_len = mtd->oobavail;
+ use_len_max = mtd->oobavail;
vary_offset = 1;
prandom_seed_state(&rnd_state, 5);

@@ -471,8 +471,8 @@ static int __init mtd_oobtest_init(void)

/* Check all eraseblocks */
use_offset = 0;
- use_len = mtd->ecclayout->oobavail;
- use_len_max = mtd->ecclayout->oobavail;
+ use_len = mtd->oobavail;
+ use_len_max = mtd->oobavail;
vary_offset = 1;
prandom_seed_state(&rnd_state, 5);
err = verify_all_eraseblocks();
@@ -480,8 +480,8 @@ static int __init mtd_oobtest_init(void)
goto out;

use_offset = 0;
- use_len = mtd->ecclayout->oobavail;
- use_len_max = mtd->ecclayout->oobavail;
+ use_len = mtd->oobavail;
+ use_len_max = mtd->oobavail;
vary_offset = 0;

/* Fourth test: try to write off end of device */
@@ -501,7 +501,7 @@ static int __init mtd_oobtest_init(void)
ops.retlen = 0;
ops.ooblen = 1;
ops.oobretlen = 0;
- ops.ooboffs = mtd->ecclayout->oobavail;
+ ops.ooboffs = mtd->oobavail;
ops.datbuf = NULL;
ops.oobbuf = writebuf;
pr_info("attempting to start write past end of OOB\n");
@@ -521,7 +521,7 @@ static int __init mtd_oobtest_init(void)
ops.retlen = 0;
ops.ooblen = 1;
ops.oobretlen = 0;
- ops.ooboffs = mtd->ecclayout->oobavail;
+ ops.ooboffs = mtd->oobavail;
ops.datbuf = NULL;
ops.oobbuf = readbuf;
pr_info("attempting to start read past end of OOB\n");
@@ -543,7 +543,7 @@ static int __init mtd_oobtest_init(void)
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
- ops.ooblen = mtd->ecclayout->oobavail + 1;
+ ops.ooblen = mtd->oobavail + 1;
ops.oobretlen = 0;
ops.ooboffs = 0;
ops.datbuf = NULL;
@@ -563,7 +563,7 @@ static int __init mtd_oobtest_init(void)
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
- ops.ooblen = mtd->ecclayout->oobavail + 1;
+ ops.ooblen = mtd->oobavail + 1;
ops.oobretlen = 0;
ops.ooboffs = 0;
ops.datbuf = NULL;
@@ -587,7 +587,7 @@ static int __init mtd_oobtest_init(void)
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
- ops.ooblen = mtd->ecclayout->oobavail;
+ ops.ooblen = mtd->oobavail;
ops.oobretlen = 0;
ops.ooboffs = 1;
ops.datbuf = NULL;
@@ -607,7 +607,7 @@ static int __init mtd_oobtest_init(void)
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
- ops.ooblen = mtd->ecclayout->oobavail;
+ ops.ooblen = mtd->oobavail;
ops.oobretlen = 0;
ops.ooboffs = 1;
ops.datbuf = NULL;
@@ -638,7 +638,7 @@ static int __init mtd_oobtest_init(void)
for (i = 0; i < ebcnt - 1; ++i) {
int cnt = 2;
int pg;
- size_t sz = mtd->ecclayout->oobavail;
+ size_t sz = mtd->oobavail;
if (bbt[i] || bbt[i + 1])
continue;
addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
@@ -673,13 +673,12 @@ static int __init mtd_oobtest_init(void)
for (i = 0; i < ebcnt - 1; ++i) {
if (bbt[i] || bbt[i + 1])
continue;
- prandom_bytes_state(&rnd_state, writebuf,
- mtd->ecclayout->oobavail * 2);
+ prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2);
addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
- ops.ooblen = mtd->ecclayout->oobavail * 2;
+ ops.ooblen = mtd->oobavail * 2;
ops.oobretlen = 0;
ops.ooboffs = 0;
ops.datbuf = NULL;
@@ -688,7 +687,7 @@ static int __init mtd_oobtest_init(void)
if (err)
goto out;
if (memcmpshow(addr, readbuf, writebuf,
- mtd->ecclayout->oobavail * 2)) {
+ mtd->oobavail * 2)) {
pr_err("error: verify failed at %#llx\n",
(long long)addr);
errcnt += 1;
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index 6536066..cb9d5ab 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -49,7 +49,6 @@ static struct nand_ecclayout spinand_oob_64 = {
17, 18, 19, 20, 21, 22,
33, 34, 35, 36, 37, 38,
49, 50, 51, 52, 53, 54, },
- .oobavail = 32,
.oobfree = {
{.offset = 8,
.length = 8},
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index f3a4857..ec76813 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -1183,22 +1183,20 @@ void jffs2_dirty_trigger(struct jffs2_sb_info *c)

int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
{
- struct nand_ecclayout *oinfo = c->mtd->ecclayout;
-
if (!c->mtd->oobsize)
return 0;

/* Cleanmarker is out-of-band, so inline size zero */
c->cleanmarker_size = 0;

- if (!oinfo || oinfo->oobavail == 0) {
+ if (mtd->oobavail == 0) {
pr_err("inconsistent device description\n");
return -EINVAL;
}

jffs2_dbg(1, "using OOB on NAND\n");

- c->oobavail = oinfo->oobavail;
+ c->oobavail = mtd->oobavail;

/* Initialise write buffer */
init_rwsem(&c->wbuf_sem);
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index cc84923..9cf13c4 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -105,7 +105,6 @@ struct mtd_oob_ops {
struct nand_ecclayout {
__u32 eccbytes;
__u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
- __u32 oobavail;
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
};

--
2.1.4

2015-12-07 22:34:03

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 02/23] mtd: inftl: kill unused oobinfo field

Signed-off-by: Boris Brezillon <[email protected]>
---
include/linux/mtd/inftl.h | 1 -
1 file changed, 1 deletion(-)

diff --git a/include/linux/mtd/inftl.h b/include/linux/mtd/inftl.h
index 02cd5f9..8255118 100644
--- a/include/linux/mtd/inftl.h
+++ b/include/linux/mtd/inftl.h
@@ -44,7 +44,6 @@ struct INFTLrecord {
unsigned int nb_blocks; /* number of physical blocks */
unsigned int nb_boot_blocks; /* number of blocks used by the bios */
struct erase_info instr;
- struct nand_ecclayout oobinfo;
};

int INFTL_mount(struct INFTLrecord *s);
--
2.1.4

2015-12-07 22:27:07

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 03/23] mtd: nftl: kill unused oobinfo field

Signed-off-by: Boris Brezillon <[email protected]>
---
include/linux/mtd/nftl.h | 1 -
1 file changed, 1 deletion(-)

diff --git a/include/linux/mtd/nftl.h b/include/linux/mtd/nftl.h
index b059629..044daa0 100644
--- a/include/linux/mtd/nftl.h
+++ b/include/linux/mtd/nftl.h
@@ -50,7 +50,6 @@ struct NFTLrecord {
unsigned int nb_blocks; /* number of physical blocks */
unsigned int nb_boot_blocks; /* number of blocks used by the bios */
struct erase_info instr;
- struct nand_ecclayout oobinfo;
};

int NFTL_mount(struct NFTLrecord *s);
--
2.1.4

2015-12-07 22:27:04

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 04/23] mtd: nand: s3c2410: kill the ->ecc_layout field

The s3c2410 is allowing board data to overload the default ECC layout
defined inside the driver, but this feature is not used by board
specific definitions.
Kill this field so that we can easily move to a model where ecclayout
are dynamically allocated by the NAND controller driver.

Signed-off-by: Boris Brezillon <[email protected]>
---
arch/arm/plat-samsung/devs.c | 9 ---------
drivers/mtd/nand/s3c2410.c | 3 ---
include/linux/platform_data/mtd-nand-s3c2410.h | 1 -
3 files changed, 13 deletions(-)

diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 8207462..a903ee8 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -710,15 +710,6 @@ static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set)
return -ENOMEM;
}

- if (set->ecc_layout) {
- ptr = kmemdup(set->ecc_layout,
- sizeof(struct nand_ecclayout), GFP_KERNEL);
- set->ecc_layout = ptr;
-
- if (!ptr)
- return -ENOMEM;
- }
-
return 0;
}

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 05105ca..b569200 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -860,9 +860,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->ecc.mode = NAND_ECC_SOFT;
#endif

- if (set->ecc_layout != NULL)
- chip->ecc.layout = set->ecc_layout;
-
if (set->disable_ecc)
chip->ecc.mode = NAND_ECC_NONE;

diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
index 36bb921..c55e42ee 100644
--- a/include/linux/platform_data/mtd-nand-s3c2410.h
+++ b/include/linux/platform_data/mtd-nand-s3c2410.h
@@ -40,7 +40,6 @@ struct s3c2410_nand_set {
char *name;
int *nr_map;
struct mtd_partition *partitions;
- struct nand_ecclayout *ecc_layout;
};

struct s3c2410_platform_nand {
--
2.1.4

2015-12-07 22:27:01

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 05/23] mtd: nand: jz4770: kill the ->ecc_layout field

->ecc_layout is not used by any board file. Kill this field to avoid any
confusion. New boards are encouraged to use the default ECC layout defined
in NAND core.

Signed-off-by: Boris Brezillon <[email protected]>
---
arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 2 --
drivers/mtd/nand/jz4740_nand.c | 3 ---
2 files changed, 5 deletions(-)

diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
index 79cff26..398733e 100644
--- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
+++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
@@ -25,8 +25,6 @@ struct jz_nand_platform_data {
int num_partitions;
struct mtd_partition *partitions;

- struct nand_ecclayout *ecc_layout;
-
unsigned char banks[JZ_NAND_NUM_BANKS];

void (*ident_callback)(struct platform_device *, struct nand_chip *,
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 5a99a93..c4fe446 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -446,9 +446,6 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->ecc.bytes = 9;
chip->ecc.strength = 4;

- if (pdata)
- chip->ecc.layout = pdata->ecc_layout;
-
chip->chip_delay = 50;
chip->cmd_ctrl = jz_nand_cmd_ctrl;
chip->select_chip = jz_nand_select_chip;
--
2.1.4

2015-12-07 22:33:38

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 06/23] mtd: nand: kill unused ->ecclayout field in platform_nand_chip struct

This field is not set in any board file and can thus be dropped.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/nand/plat_nand.c | 1 -
include/linux/mtd/nand.h | 2 --
2 files changed, 3 deletions(-)

diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index 06ac6c6..71aaa09 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -74,7 +74,6 @@ static int plat_nand_probe(struct platform_device *pdev)
data->chip.bbt_options |= pdata->chip.bbt_options;

data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
- data->chip.ecc.layout = pdata->chip.ecclayout;
data->chip.ecc.mode = NAND_ECC_SOFT;

platform_set_drvdata(pdev, data);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index fad634e..cbedcb0 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -866,7 +866,6 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
* @chip_delay: R/B delay value in us
* @options: Option flags, e.g. 16bit buswidth
* @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH
- * @ecclayout: ECC layout info structure
* @part_probe_types: NULL-terminated array of probe types
*/
struct platform_nand_chip {
@@ -874,7 +873,6 @@ struct platform_nand_chip {
int chip_offset;
int nr_partitions;
struct mtd_partition *partitions;
- struct nand_ecclayout *ecclayout;
int chip_delay;
unsigned int options;
unsigned int bbt_options;
--
2.1.4

2015-12-07 22:27:09

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 07/23] staging: mt29f_spinand: kill unused ecclayout field

The spinand_info struct embeds a pointer to an ecclayout definition, but
this field is never used in the mt29f driver.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/staging/mt29f_spinand/mt29f_spinand.h | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.h b/drivers/staging/mt29f_spinand/mt29f_spinand.h
index ae62975..457dc7f 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.h
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.h
@@ -78,7 +78,6 @@
#define BL_ALL_UNLOCKED 0

struct spinand_info {
- struct nand_ecclayout *ecclayout;
struct spi_device *spi;
void *priv;
};
--
2.1.4

2015-12-07 22:32:45

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 08/23] mtd: nand: lpc32xx_mlc: fix ecc.size

According to the ECC layout description the actual ecc.size is 512 bytes
and not mtd->writesize.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/nand/lpc32xx_mlc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index 57c4b71..0ee81a0 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -751,7 +751,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}

nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = mtd->writesize;
+ nand_chip->ecc.size = 512;
nand_chip->ecc.layout = &lpc32xx_nand_oob;
host->mlcsubpages = mtd->writesize / 512;

--
2.1.4

2015-12-07 22:27:13

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 09/23] mtd: nand: vf610: remove useless mtd->ecclayout assignment

The NAND core layer is already taking care of ecclayout propagation. Remove
this useless assignment.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/nand/vf610_nfc.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 1c86c6b..0413e24 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -794,8 +794,6 @@ static int vf610_nfc_probe(struct platform_device *pdev)
goto error;
}

- /* propagate ecc.layout to mtd_info */
- mtd->ecclayout = chip->ecc.layout;
chip->ecc.read_page = vf610_nfc_read_page;
chip->ecc.write_page = vf610_nfc_write_page;

--
2.1.4

2015-12-07 22:32:11

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 10/23] mtd: nand: simplify nand_bch_init() usage

nand_bch_init() requires several arguments which could directly be deduced
from the mtd device. Get rid of those useless parameters.

nand_bch_init() is also requiring the caller to provide a proper eccbytes
value, while this value could be deduced from the ecc.size and
ecc.strength value. Fallback to eccbytes calculation when it is set to 0.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/nand/nand_base.c | 6 ++----
drivers/mtd/nand/nand_bch.c | 27 +++++++++++++++++----------
drivers/mtd/nand/omap2.c | 28 ++++++++++++----------------
include/linux/mtd/nand_bch.h | 8 ++------
4 files changed, 33 insertions(+), 36 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 1107f5c1..b99b442 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4247,10 +4247,8 @@ int nand_scan_tail(struct mtd_info *mtd)
}

/* See nand_bch_init() for details. */
- ecc->bytes = DIV_ROUND_UP(
- ecc->strength * fls(8 * ecc->size), 8);
- ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
- &ecc->layout);
+ ecc->bytes = 0;
+ ecc->priv = nand_bch_init(mtd);
if (!ecc->priv) {
pr_warn("BCH ECC initialization failed!\n");
BUG();
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index 3803e0b..3456c20 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -107,9 +107,6 @@ EXPORT_SYMBOL(nand_bch_correct_data);
/**
* nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
* @mtd: MTD block structure
- * @eccsize: ecc block size in bytes
- * @eccbytes: ecc length in bytes
- * @ecclayout: output default layout
*
* Returns:
* a pointer to a new NAND BCH control structure, or NULL upon failure
@@ -123,14 +120,21 @@ EXPORT_SYMBOL(nand_bch_correct_data);
* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
* @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
*/
-struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
- struct nand_ecclayout **ecclayout)
+struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
{
+ struct nand_chip *nand = mtd_to_nand(mtd);
unsigned int m, t, eccsteps, i;
- struct nand_ecclayout *layout;
+ struct nand_ecclayout *layout = nand->ecc.layout;
struct nand_bch_control *nbc = NULL;
unsigned char *erased_page;
+ unsigned int eccsize = nand->ecc.size;
+ unsigned int eccbytes = nand->ecc.bytes;
+ unsigned int eccstrength = nand->ecc.strength;
+
+ if (!eccbytes && eccstrength) {
+ eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
+ nand->ecc.bytes = eccbytes;
+ }

if (!eccsize || !eccbytes) {
printk(KERN_WARNING "ecc parameters not supplied\n");
@@ -158,7 +162,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
eccsteps = mtd->writesize/eccsize;

/* if no ecc placement scheme was provided, build one */
- if (!*ecclayout) {
+ if (!layout) {

/* handle large page devices only */
if (mtd->oobsize < 64) {
@@ -184,7 +188,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
layout->oobfree[0].offset = 2;
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;

- *ecclayout = layout;
+ nand->ecc.layout = layout;
}

/* sanity checks */
@@ -192,7 +196,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
goto fail;
}
- if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
+ if (layout->eccbytes != (eccsteps*eccbytes)) {
printk(KERN_WARNING "invalid ecc layout\n");
goto fail;
}
@@ -216,6 +220,9 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
for (i = 0; i < eccbytes; i++)
nbc->eccmask[i] ^= 0xff;

+ if (!eccstrength)
+ nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
+
return nbc;
fail:
nand_bch_free(nbc);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index e307576..a2f015d 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1820,13 +1820,19 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error;
}

+ /*
+ * Bail out earlier to let NAND_ECC_SOFT code create its own
+ * ecclayout instead of using ours.
+ */
+ if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
+ nand_chip->ecc.mode = NAND_ECC_SOFT;
+ goto scan_tail;
+ }
+
/* populate MTD interface based on ECC scheme */
ecclayout = &info->oobinfo;
+ nand_chip->ecc.layout = ecclayout;
switch (info->ecc_opt) {
- case OMAP_ECC_HAM1_CODE_SW:
- nand_chip->ecc.mode = NAND_ECC_SOFT;
- break;
-
case OMAP_ECC_HAM1_CODE_HW:
pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
nand_chip->ecc.mode = NAND_ECC_HW;
@@ -1874,10 +1880,7 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->oobfree->offset = 1 +
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* software bch library is used for locating errors */
- nand_chip->ecc.priv = nand_bch_init(mtd,
- nand_chip->ecc.size,
- nand_chip->ecc.bytes,
- &ecclayout);
+ nand_chip->ecc.priv = nand_bch_init(mtd);
if (!nand_chip->ecc.priv) {
dev_err(&info->pdev->dev, "unable to use BCH library\n");
err = -EINVAL;
@@ -1938,10 +1941,7 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->oobfree->offset = 1 +
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* software bch library is used for locating errors */
- nand_chip->ecc.priv = nand_bch_init(mtd,
- nand_chip->ecc.size,
- nand_chip->ecc.bytes,
- &ecclayout);
+ nand_chip->ecc.priv = nand_bch_init(mtd);
if (!nand_chip->ecc.priv) {
dev_err(&info->pdev->dev, "unable to use BCH library\n");
err = -EINVAL;
@@ -2015,9 +2015,6 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error;
}

- if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW)
- goto scan_tail;
-
/* all OOB bytes from oobfree->offset till end off OOB are free */
ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
/* check if NAND device's OOB is enough to store ECC signatures */
@@ -2028,7 +2025,6 @@ static int omap_nand_probe(struct platform_device *pdev)
err = -EINVAL;
goto return_error;
}
- nand_chip->ecc.layout = ecclayout;

scan_tail:
/* second phase scan */
diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h
index 74acf53..04f2c8b 100644
--- a/include/linux/mtd/nand_bch.h
+++ b/include/linux/mtd/nand_bch.h
@@ -32,9 +32,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
/*
* Initialize BCH encoder/decoder
*/
-struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
- unsigned int eccbytes, struct nand_ecclayout **ecclayout);
+struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
/*
* Release BCH encoder/decoder resources
*/
@@ -58,9 +56,7 @@ nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
return -1;
}

-static inline struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
- unsigned int eccbytes, struct nand_ecclayout **ecclayout)
+static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
{
return NULL;
}
--
2.1.4

2015-12-07 22:27:18

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 11/23] mtd: add mtd_eccpos(), mtd_oobfree() and mtd_eccbytes() helper functions

In order to make the ecclayout definition completely dynamic we need to
rework the way these different ECC layouts are defined and iterated.

Create the mtd_eccpos(), mtd_oobfree() and mtd_eccbytes() helpers to hide
ecclayout definition internals to their users.

Signed-off-by: Boris Brezillon <[email protected]>
---
include/linux/mtd/mtd.h | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)

diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 9cf13c4..25e3d0f 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -253,6 +253,38 @@ struct mtd_info {
int usecount;
};

+static inline int mtd_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (!mtd->ecclayout)
+ return -ENOTSUPP;
+
+ if (eccbyte >= mtd->ecclayout->eccbytes)
+ return -ERANGE;
+
+ return mtd->ecclayout->eccpos[eccbyte];
+}
+
+static inline int mtd_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ memset(oobfree, 0, sizeof(*oobfree));
+
+ if (!mtd->ecclayout)
+ return -ENOTSUPP;
+
+ if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE)
+ return -ERANGE;
+
+ *oobfree = mtd->ecclayout->oobfree[section];
+
+ return 0;
+}
+
+static inline int mtd_eccbytes(struct mtd_info *mtd)
+{
+ return mtd->ecclayout ? mtd->ecclayout->eccbytes : 0;
+}
+
static inline void mtd_set_of_node(struct mtd_info *mtd,
struct device_node *np)
{
--
2.1.4

2015-12-07 22:27:26

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 12/23] mtd: use mtd_eccpos() and mtd_oobfree() where appropriate

The mtd_eccpos(), mtd_oobfree() and mtd_eccbytes() helper functions have
been added to avoid direct accesses to the ecclayout, and thus allow for
future rework.
Use these helpers in all places where the oobfree[] and eccpos[] arrays
are referenced.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/mtdchar.c | 79 ++++++++++++++++++++++++--------
drivers/mtd/mtdswap.c | 4 +-
drivers/mtd/nand/atmel_nand.c | 21 ++++-----
drivers/mtd/nand/fsl_ifc_nand.c | 2 +-
drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 9 ++--
drivers/mtd/nand/lpc32xx_slc.c | 4 +-
drivers/mtd/nand/nand_base.c | 83 ++++++++++++++++++----------------
drivers/mtd/nand/nand_bch.c | 2 +-
drivers/mtd/nand/omap2.c | 11 ++---
drivers/mtd/onenand/onenand_base.c | 61 +++++++++++++------------
10 files changed, 163 insertions(+), 113 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 6d19835..66d0898 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -472,31 +472,78 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
* nand_ecclayout flexibly (i.e. the struct may change size in new
* releases without requiring major rewrites).
*/
-static int shrink_ecclayout(const struct nand_ecclayout *from,
- struct nand_ecclayout_user *to)
+static int shrink_ecclayout(struct mtd_info *mtd,
+ struct nand_ecclayout_user *to)
{
int i;

- if (!from || !to)
+ if (!mtd || !to)
return -EINVAL;

memset(to, 0, sizeof(*to));

- to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES);
- for (i = 0; i < to->eccbytes; i++)
- to->eccpos[i] = from->eccpos[i];
+ to->eccbytes = 0;
+ for (i = 0; i < MTD_MAX_ECCPOS_ENTRIES; i++) {
+ int pos = mtd_eccpos(mtd, i);
+
+ if (pos < 0)
+ break;
+
+ to->eccpos[i] = pos;
+ to->eccbytes++;
+ }

for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
- if (from->oobfree[i].length == 0 &&
- from->oobfree[i].offset == 0)
+ mtd_oobfree(mtd, i, &to->oobfree[i]);
+ if (to->oobfree[i].length == 0 &&
+ to->oobfree[i].offset == 0)
break;
- to->oobavail += from->oobfree[i].length;
- to->oobfree[i] = from->oobfree[i];
+ to->oobavail += to->oobfree[i].length;
}

return 0;
}

+static int get_oobinfo(struct mtd_info *mtd, struct nand_oobinfo *to)
+{
+ int i;
+
+ if (!mtd || !to)
+ return -EINVAL;
+
+ memset(to, 0, sizeof(*to));
+
+ to->eccbytes = 0;
+ for (i = 0; i < ARRAY_SIZE(to->eccpos); i++) {
+ int pos = mtd_eccpos(mtd, i);
+
+ if (pos < 0)
+ break;
+
+ to->eccpos[i] = pos;
+ to->eccbytes++;
+ }
+
+ if (i == ARRAY_SIZE(to->eccpos))
+ return -EINVAL;
+
+ for (i = 0; i < 8; i++) {
+ struct nand_oobfree oobfree;
+
+ mtd_oobfree(mtd, i, &oobfree);
+ if (oobfree.length == 0 &&
+ oobfree.offset == 0)
+ break;
+
+ to->oobfree[i][0] = oobfree.offset;
+ to->oobfree[i][1] = oobfree.length;
+ }
+
+ to->useecc = MTD_NANDECC_AUTOPLACE;
+
+ return 0;
+}
+
static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
struct blkpg_ioctl_arg *arg)
{
@@ -817,14 +864,10 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)

if (!mtd->ecclayout)
return -EOPNOTSUPP;
- if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos))
- return -EINVAL;

- oi.useecc = MTD_NANDECC_AUTOPLACE;
- memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
- memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
- sizeof(oi.oobfree));
- oi.eccbytes = mtd->ecclayout->eccbytes;
+ ret = get_oobinfo(mtd, &oi);
+ if (ret)
+ return ret;

if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
return -EFAULT;
@@ -920,7 +963,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
if (!usrlay)
return -ENOMEM;

- shrink_ecclayout(mtd->ecclayout, usrlay);
+ shrink_ecclayout(mtd, usrlay);

if (copy_to_user(argp, usrlay, sizeof(*usrlay)))
ret = -EFAULT;
diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index d330eb1..6fe47b0 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -1417,7 +1417,6 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
unsigned long part;
unsigned int eblocks, eavailable, bad_blocks, spare_cnt;
uint64_t swap_size, use_size, size_limit;
- struct nand_ecclayout *oinfo;
int ret;

parts = &partitions[0];
@@ -1447,8 +1446,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
return;
}

- oinfo = mtd->ecclayout;
- if (!oinfo) {
+ if (mtd_oobfree(mtd, 0) < 0) {
printk(KERN_ERR "%s: mtd%d does not have OOB\n",
MTDSWAP_PREFIX, mtd->index);
return;
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index f4e1f91..da16b1a 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -833,7 +833,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
err_byte = ecc[tmp];
ecc[tmp] ^= (1 << bit_pos);

- pos = tmp + nand_chip->ecc.layout->eccpos[0];
+ pos = tmp + mtd_eccpos(mtd, 0);
dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
pos, bit_pos, err_byte, ecc[tmp]);
}
@@ -922,7 +922,6 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
struct atmel_nand_host *host = chip->priv;
int eccsize = chip->ecc.size * chip->ecc.steps;
uint8_t *oob = chip->oob_poi;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
uint32_t stat;
unsigned long end_time;
int bitflips = 0;
@@ -944,7 +943,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,

stat = pmecc_readl_relaxed(host->ecc, ISR);
if (stat != 0) {
- bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]);
+ bitflips = pmecc_correction(mtd, stat, buf,
+ &oob[mtd_eccpos(mtd, 0)]);
if (bitflips < 0)
/* uncorrectable errors */
return 0;
@@ -958,7 +958,6 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
int page)
{
struct atmel_nand_host *host = chip->priv;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
int i, j;
unsigned long end_time;

@@ -981,7 +980,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
int pos;

pos = i * chip->ecc.bytes + j;
- chip->oob_poi[eccpos[pos]] =
+ chip->oob_poi[mtd_eccpos(mtd, pos)] =
pmecc_readb_ecc_relaxed(host->ecc, i, j);
}
}
@@ -1044,9 +1043,9 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)

ecc_layout = nand_chip->ecc.layout;
pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
- pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]);
+ pmecc_writel(host->ecc, SADDR, mtd_eccpos(mtd, 0));
pmecc_writel(host->ecc, EADDR,
- ecc_layout->eccpos[ecc_layout->eccbytes - 1]);
+ mtd_eccpos(mtd, ecc_layout->eccbytes - 1));
/* See datasheet about PMECC Clock Control Register */
pmecc_writel(host->ecc, CLK, 2);
pmecc_writel(host->ecc, IDR, 0xff);
@@ -1340,7 +1339,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
{
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
+ int eccpos = mtd_eccpos(mtd, 0);
uint8_t *p = buf;
uint8_t *oob = chip->oob_poi;
uint8_t *ecc_pos;
@@ -1363,7 +1362,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_buf(mtd, p, eccsize);

/* move to ECC position if needed */
- if (eccpos[0] != 0) {
+ if (eccpos != 0) {
/* This only works on large pages
* because the ECC controller waits for
* NAND_CMD_RNDOUTSTART after the
@@ -1371,11 +1370,11 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
* anyway, for small pages, the eccpos[0] == 0
*/
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
- mtd->writesize + eccpos[0], -1);
+ mtd->writesize + eccpos, -1);
}

/* the ECC controller needs to read the ECC just after the data */
- ecc_pos = oob + eccpos[0];
+ ecc_pos = oob + eccpos;
chip->read_buf(mtd, ecc_pos, eccbytes);

/* check if there's an error */
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index f260831..610308e 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -266,7 +266,7 @@ static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
}

for (i = 0; i < chip->ecc.layout->eccbytes; i++) {
- int pos = chip->ecc.layout->eccpos[i];
+ int pos = mtd_eccpos(mtd, i);

if (__raw_readb(&oob[pos]) != 0xff)
return 0;
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 5a9b696..c208f5e 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1325,18 +1325,19 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int
gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
{
- struct nand_oobfree *of = mtd->ecclayout->oobfree;
+ struct nand_oobfree of = { };
int status = 0;

/* Do we have available oob area? */
- if (!of->length)
+ mtd_oobfree(mtd, 0, &of);
+ if (!of.length)
return -EPERM;

if (!nand_is_slc(chip))
return -EPERM;

- chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of->offset, page);
- chip->write_buf(mtd, chip->oob_poi + of->offset, of->length);
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of.offset, page);
+ chip->write_buf(mtd, chip->oob_poi + of.offset, of.length);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);

status = chip->waitfunc(mtd, chip);
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index 277626e..47dcfddd 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -621,7 +621,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);

/* Pointer to ECC data retrieved from NAND spare area */
- oobecc = chip->oob_poi + chip->ecc.layout->eccpos[0];
+ oobecc = chip->oob_poi + mtd_eccpos(mtd, 0);

for (i = 0; i < chip->ecc.steps; i++) {
stat = chip->ecc.correct(mtd, buf, oobecc,
@@ -667,7 +667,7 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
int oob_required, int page)
{
struct lpc32xx_nand_host *host = chip->priv;
- uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0];
+ uint8_t *pb = chip->oob_poi + mtd_eccpos(mtd, 0);
int error;

/* Write data, calculate ECC on outbound data */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index b99b442..30a0721 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1315,7 +1315,6 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *p = buf;
uint8_t *ecc_calc = chip->buffers->ecccalc;
uint8_t *ecc_code = chip->buffers->ecccode;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
unsigned int max_bitflips = 0;

chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
@@ -1324,7 +1323,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
chip->ecc.calculate(mtd, p, &ecc_calc[i]);

for (i = 0; i < chip->ecc.total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
+ ecc_code[i] = chip->oob_poi[mtd_eccpos(mtd, i)];

eccsteps = chip->ecc.steps;
p = buf;
@@ -1357,7 +1356,6 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
int start_step, end_step, num_steps;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
uint8_t *p;
int data_col_addr, i, gaps = 0;
int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
@@ -1392,7 +1390,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
* ecc.pos. Let's make sure that there are no gaps in ECC positions.
*/
for (i = 0; i < eccfrag_len - 1; i++) {
- if (eccpos[i + index] + 1 != eccpos[i + index + 1]) {
+ if (mtd_eccpos(mtd, i + index) + 1 !=
+ mtd_eccpos(mtd, i + index + 1)) {
gaps = 1;
break;
}
@@ -1405,11 +1404,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
* Send the command to read the particular ECC bytes take care
* about buswidth alignment in read_buf.
*/
- aligned_pos = eccpos[index] & ~(busw - 1);
+ aligned_pos = mtd_eccpos(mtd, index) & ~(busw - 1);
aligned_len = eccfrag_len;
- if (eccpos[index] & (busw - 1))
+ if (mtd_eccpos(mtd, index) & (busw - 1))
aligned_len++;
- if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
+ if (mtd_eccpos(mtd, index + (num_steps * chip->ecc.bytes)) &
+ (busw - 1))
aligned_len++;

chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
@@ -1418,7 +1418,8 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
}

for (i = 0; i < eccfrag_len; i++)
- chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]];
+ chip->buffers->ecccode[i] =
+ chip->oob_poi[mtd_eccpos(mtd, i + index)];

p = bufpoi + data_col_addr;
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
@@ -1455,7 +1456,6 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *p = buf;
uint8_t *ecc_calc = chip->buffers->ecccalc;
uint8_t *ecc_code = chip->buffers->ecccode;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
unsigned int max_bitflips = 0;

for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
@@ -1466,7 +1466,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);

for (i = 0; i < chip->ecc.total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
+ ecc_code[i] = chip->oob_poi[mtd_eccpos(mtd, i)];

eccsteps = chip->ecc.steps;
p = buf;
@@ -1507,7 +1507,6 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *ecc_code = chip->buffers->ecccode;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
uint8_t *ecc_calc = chip->buffers->ecccalc;
unsigned int max_bitflips = 0;

@@ -1517,7 +1516,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);

for (i = 0; i < chip->ecc.total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
+ ecc_code[i] = chip->oob_poi[mtd_eccpos(mtd, i)];

for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
@@ -1603,9 +1602,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
* @ops: oob ops structure
* @len: size of oob to transfer
*/
-static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
+static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
struct mtd_oob_ops *ops, size_t len)
{
+ struct nand_chip *chip = mtd->priv;
+
switch (ops->mode) {

case MTD_OPS_PLACE_OOB:
@@ -1614,24 +1615,26 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
return oob + len;

case MTD_OPS_AUTO_OOB: {
- struct nand_oobfree *free = chip->ecc.layout->oobfree;
+ struct nand_oobfree free = { };
uint32_t boffs = 0, roffs = ops->ooboffs;
size_t bytes = 0;
+ int i = 0;

- for (; free->length && len; free++, len -= bytes) {
+ for (mtd_oobfree(mtd, i++, &free); free.length && len;
+ mtd_oobfree(mtd, i++, &free), len -= bytes) {
/* Read request not from offset 0? */
if (unlikely(roffs)) {
- if (roffs >= free->length) {
- roffs -= free->length;
+ if (roffs >= free.length) {
+ roffs -= free.length;
continue;
}
- boffs = free->offset + roffs;
+ boffs = free.offset + roffs;
bytes = min_t(size_t, len,
- (free->length - roffs));
+ (free.length - roffs));
roffs = 0;
} else {
- bytes = min_t(size_t, len, free->length);
- boffs = free->offset;
+ bytes = min_t(size_t, len, free.length);
+ boffs = free.offset;
}
memcpy(oob, chip->oob_poi + boffs, bytes);
oob += bytes;
@@ -1772,7 +1775,7 @@ read_retry:
int toread = min(oobreadlen, max_oobsize);

if (toread) {
- oob = nand_transfer_oob(chip,
+ oob = nand_transfer_oob(mtd,
oob, ops, toread);
oobreadlen -= toread;
}
@@ -2073,7 +2076,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
break;

len = min(len, readlen);
- buf = nand_transfer_oob(chip, buf, ops, len);
+ buf = nand_transfer_oob(mtd, buf, ops, len);

if (chip->options & NAND_NEED_READRDY) {
/* Apply delay or wait for ready/busy pin */
@@ -2237,14 +2240,13 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
int eccsteps = chip->ecc.steps;
uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
- uint32_t *eccpos = chip->ecc.layout->eccpos;

/* Software ECC calculation */
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
chip->ecc.calculate(mtd, p, &ecc_calc[i]);

for (i = 0; i < chip->ecc.total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
+ chip->oob_poi[mtd_eccpos(mtd, i)] = ecc_calc[i];

return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
}
@@ -2266,7 +2268,6 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
int eccsteps = chip->ecc.steps;
uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
- uint32_t *eccpos = chip->ecc.layout->eccpos;

for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
@@ -2275,7 +2276,7 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
}

for (i = 0; i < chip->ecc.total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
+ chip->oob_poi[mtd_eccpos(mtd, i)] = ecc_calc[i];

chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);

@@ -2303,7 +2304,6 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes;
int ecc_steps = chip->ecc.steps;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
uint32_t start_step = offset / ecc_size;
uint32_t end_step = (offset + data_len - 1) / ecc_size;
int oob_bytes = mtd->oobsize / ecc_steps;
@@ -2336,7 +2336,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
/* this include masked-value(0xFF) for unwritten subpages */
ecc_calc = chip->buffers->ecccalc;
for (i = 0; i < chip->ecc.total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
+ chip->oob_poi[mtd_eccpos(mtd, i)] = ecc_calc[i];

/* write OOB buffer to NAND device */
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -2488,24 +2488,26 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
return oob + len;

case MTD_OPS_AUTO_OOB: {
- struct nand_oobfree *free = chip->ecc.layout->oobfree;
+ struct nand_oobfree free = { };
uint32_t boffs = 0, woffs = ops->ooboffs;
size_t bytes = 0;
+ int i = 0;

- for (; free->length && len; free++, len -= bytes) {
+ for (mtd_oobfree(mtd, i++, &free); free.length && len;
+ mtd_oobfree(mtd, i++, &free), len -= bytes) {
/* Write request not from offset 0? */
if (unlikely(woffs)) {
- if (woffs >= free->length) {
- woffs -= free->length;
+ if (woffs >= free.length) {
+ woffs -= free.length;
continue;
}
- boffs = free->offset + woffs;
+ boffs = free.offset + woffs;
bytes = min_t(size_t, len,
- (free->length - woffs));
+ (free.length - woffs));
woffs = 0;
} else {
- bytes = min_t(size_t, len, free->length);
- boffs = free->offset;
+ bytes = min_t(size_t, len, free.length);
+ boffs = free.offset;
}
memcpy(chip->oob_poi + boffs, oob, bytes);
oob += bytes;
@@ -4087,6 +4089,7 @@ int nand_scan_tail(struct mtd_info *mtd)
int i;
struct nand_chip *chip = mtd->priv;
struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_oobfree oobfree = { };
struct nand_buffers *nbuf;

/* New bad blocks should be marked in OOB, flash-based BBT, or both */
@@ -4284,8 +4287,10 @@ int nand_scan_tail(struct mtd_info *mtd)
* the out of band area.
*/
mtd->oobavail = 0;
- for (i = 0; ecc->layout->oobfree[i].length; i++)
- mtd->oobavail += ecc->layout->oobfree[i].length;
+ i = 0;
+ for (mtd_oobfree(mtd, i++, &oobfree); oobfree.length;
+ mtd_oobfree(mtd, i++, &oobfree))
+ mtd->oobavail += oobfree.length;

/* ECC sanity check: warn if it's too weak */
if (!nand_ecc_strength_good(mtd))
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index 3456c20..9cff544 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -196,7 +196,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
goto fail;
}
- if (layout->eccbytes != (eccsteps*eccbytes)) {
+ if (mtd_eccbytes(mtd) != (eccsteps*eccbytes)) {
printk(KERN_WARNING "invalid ecc layout\n");
goto fail;
}
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index a2f015d..6a598b1 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1509,7 +1509,6 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
{
int i;
uint8_t *ecc_calc = chip->buffers->ecccalc;
- uint32_t *eccpos = chip->ecc.layout->eccpos;

/* Enable GPMC ecc engine */
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
@@ -1521,7 +1520,7 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
chip->ecc.calculate(mtd, buf, &ecc_calc[0]);

for (i = 0; i < chip->ecc.total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
+ chip->oob_poi[mtd_eccpos(mtd, i)] = ecc_calc[i];

/* Write ecc vector to OOB area */
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -1548,9 +1547,9 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
{
uint8_t *ecc_calc = chip->buffers->ecccalc;
uint8_t *ecc_code = chip->buffers->ecccode;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
- uint8_t *oob = &chip->oob_poi[eccpos[0]];
- uint32_t oob_pos = mtd->writesize + chip->ecc.layout->eccpos[0];
+ int ecc0pos = mtd_eccpos(mtd, 0);
+ uint8_t *oob = &chip->oob_poi[ecc0pos];
+ uint32_t oob_pos = mtd->writesize + ecc0pos;
int stat;
unsigned int max_bitflips = 0;

@@ -1567,7 +1566,7 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
/* Calculate ecc bytes */
chip->ecc.calculate(mtd, buf, ecc_calc);

- memcpy(ecc_code, &chip->oob_poi[eccpos[0]], chip->ecc.total);
+ memcpy(ecc_code, &chip->oob_poi[ecc0pos], chip->ecc.total);

stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);

diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index d70bbfd..25e6bf2 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1024,27 +1024,29 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
int thislen)
{
struct onenand_chip *this = mtd->priv;
- struct nand_oobfree *free;
+ struct nand_oobfree free = { };
int readcol = column;
int readend = column + thislen;
int lastgap = 0;
- unsigned int i;
+ unsigned int i = 0;
uint8_t *oob_buf = this->oob_buf;

- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ for (mtd_oobfree(mtd, i++, &free); free.length;
+ mtd_oobfree(mtd, i++, &free)) {
if (readcol >= lastgap)
- readcol += free->offset - lastgap;
+ readcol += free.offset - lastgap;
if (readend >= lastgap)
- readend += free->offset - lastgap;
- lastgap = free->offset + free->length;
+ readend += free.offset - lastgap;
+ lastgap = free.offset + free.length;
}
this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- int free_end = free->offset + free->length;
- if (free->offset < readend && free_end > readcol) {
- int st = max_t(int,free->offset,readcol);
+ memset(&free, 0, sizeof(free));
+ i = 0;
+ for (mtd_oobfree(mtd, i++, &free); free.length;
+ mtd_oobfree(mtd, i++, &free)) {
+ int free_end = free.offset + free.length;
+ if (free.offset < readend && free_end > readcol) {
+ int st = max_t(int,free.offset,readcol);
int ed = min_t(int,free_end,readend);
int n = ed - st;
memcpy(buf, oob_buf + st, n);
@@ -1816,26 +1818,27 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
const u_char *buf, int column, int thislen)
{
- struct onenand_chip *this = mtd->priv;
- struct nand_oobfree *free;
+ struct nand_oobfree free = { };
int writecol = column;
int writeend = column + thislen;
int lastgap = 0;
- unsigned int i;
+ unsigned int i = 0;

- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ for (mtd_oobfree(mtd, i++, &free); free.length;
+ mtd_oobfree(mtd, i++, &free)) {
if (writecol >= lastgap)
- writecol += free->offset - lastgap;
+ writecol += free.offset - lastgap;
if (writeend >= lastgap)
- writeend += free->offset - lastgap;
- lastgap = free->offset + free->length;
+ writeend += free.offset - lastgap;
+ lastgap = free.offset + free.length;
}
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- int free_end = free->offset + free->length;
- if (free->offset < writeend && free_end > writecol) {
- int st = max_t(int,free->offset,writecol);
+ memset(&free, 0, sizeof(free));
+ i = 0;
+ for (mtd_oobfree(mtd, i++, &free); free.length;
+ mtd_oobfree(mtd, i++, &free)) {
+ int free_end = free.offset + free.length;
+ if (free.offset < writeend && free_end > writecol) {
+ int st = max_t(int,free.offset,writecol);
int ed = min_t(int,free_end,writeend);
int n = ed - st;
memcpy(oob_buf + st, buf, n);
@@ -3942,6 +3945,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
{
int i, ret;
struct onenand_chip *this = mtd->priv;
+ struct nand_oobfree oobfree = {};

if (!this->read_word)
this->read_word = onenand_readw;
@@ -4050,9 +4054,10 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
* the out of band area
*/
mtd->oobavail = 0;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
- this->ecclayout->oobfree[i].length; i++)
- mtd->oobavail += this->ecclayout->oobfree[i].length;
+ i = 0;
+ for (mtd_oobfree(mtd, i++, &oobfree); oobfree.length;
+ mtd_oobfree(mtd, i++, &oobfree))
+ mtd->oobavail += oobfree.length;

mtd->ecclayout = this->ecclayout;
mtd->ecc_strength = 1;
--
2.1.4

2015-12-07 22:30:58

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 13/23] mtd: add mtd_set_ecclayout() helper function

Add an mtd_set_ecclayout() helper function to avoid direct accesses to the
mtd->ecclayout field. This will ease future refactor of ECC layout
definition.

Signed-off-by: Boris Brezillon <[email protected]>
---
include/linux/mtd/mtd.h | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 25e3d0f..80e32fa 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -253,6 +253,12 @@ struct mtd_info {
int usecount;
};

+static inline void mtd_set_ecclayout(struct mtd_info *mtd,
+ struct nand_ecclayout *ecclayout)
+{
+ mtd->ecclayout = ecclayout;
+}
+
static inline int mtd_eccpos(struct mtd_info *mtd, int eccbyte)
{
if (!mtd->ecclayout)
--
2.1.4

2015-12-07 22:30:56

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 14/23] mtd: use mtd_set_ecclayout() where appropriate

Use the mtd_set_ecclayout() helper instead of directly assigning the
mtd->ecclayout field.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/devices/docg3.c | 2 +-
drivers/mtd/mtdconcat.c | 2 +-
drivers/mtd/mtdpart.c | 2 +-
drivers/mtd/nand/nand_base.c | 2 +-
drivers/mtd/onenand/onenand_base.c | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index e7b2e43..6b516e1 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -1857,7 +1857,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
mtd->_read_oob = doc_read_oob;
mtd->_write_oob = doc_write_oob;
mtd->_block_isbad = doc_block_isbad;
- mtd->ecclayout = &docg3_oobinfo;
+ mtd_set_ecclayout(mtd, &docg3_oobinfo);
mtd->oobavail = 8;
mtd->ecc_strength = DOC_ECC_BCH_T;

diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 239a8c8..481565e 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -777,7 +777,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c

}

- concat->mtd.ecclayout = subdev[0]->ecclayout;
+ mtd_set_ecclayout(&concat->mtd, subdev[0]->ecclayout);

concat->num_subdev = num_devs;
concat->mtd.name = name;
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index c32b127..244faa8 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -536,7 +536,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
part->name);
}

- slave->mtd.ecclayout = master->ecclayout;
+ mtd_set_ecclayout(&slave->mtd, master->ecclayout);
slave->mtd.ecc_step_size = master->ecc_step_size;
slave->mtd.ecc_strength = master->ecc_strength;
slave->mtd.bitflip_threshold = master->bitflip_threshold;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 30a0721..2b334cf 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4365,7 +4365,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->writebufsize = mtd->writesize;

/* propagate ecc info to mtd_info */
- mtd->ecclayout = ecc->layout;
+ mtd_set_ecclayout(mtd, ecc->layout);
mtd->ecc_strength = ecc->strength;
mtd->ecc_step_size = ecc->size;
/*
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 25e6bf2..b5937b7 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -4059,7 +4059,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd_oobfree(mtd, i++, &oobfree))
mtd->oobavail += oobfree.length;

- mtd->ecclayout = this->ecclayout;
+ mtd_set_ecclayout(mtd, this->ecclayout);
mtd->ecc_strength = 1;

/* Fill in remaining MTD driver data */
--
2.1.4

2015-12-07 22:27:37

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 15/23] mtd: create an mtd_ooblayout_ops struct to ease ECC layout definition

ECC layout definitions are currently exposed using the nand_ecclayout
struct which embeds oobfree and eccpos arrays with predefined size.
This approach was acceptable when the NAND were providing relatively small
OOB regions, but MLC and TLC now provide OOB regions of several hundreds
of bytes, which implies a non negigible size penalty for everybody even
those who only need to support legacy NANDs.

Create an mtd_ooblayout_ops interface providing the same functionality
(expose the ECC and OOBFREE layout) without the need for this huge
structure.

The mtd->ecclayout is now deprecated and should be replaced by the
equivalent mtd_ooblayout_ops. In the meantime we provide a wrapper around
the ->ecclayout field to ease migration to this new model.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/mtdchar.c | 4 ++--
drivers/mtd/mtdconcat.c | 2 +-
drivers/mtd/mtdcore.c | 44 ++++++++++++++++++++++++++++++++++++++++
drivers/mtd/mtdpart.c | 22 +++++++++++++++++++-
include/linux/mtd/mtd.h | 53 +++++++++++++++++++++++++++++++++----------------
5 files changed, 104 insertions(+), 21 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 66d0898..c03b678 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -862,7 +862,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
{
struct nand_oobinfo oi;

- if (!mtd->ecclayout)
+ if (!mtd->ooblayout)
return -EOPNOTSUPP;

ret = get_oobinfo(mtd, &oi);
@@ -956,7 +956,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
{
struct nand_ecclayout_user *usrlay;

- if (!mtd->ecclayout)
+ if (!mtd->ooblayout)
return -EOPNOTSUPP;

usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 481565e..d573606 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -777,7 +777,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c

}

- mtd_set_ecclayout(&concat->mtd, subdev[0]->ecclayout);
+ mtd_set_ooblayout(&concat->mtd, subdev[0]->ooblayout);

concat->num_subdev = num_devs;
concat->mtd.name = name;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 62f83b0..d87f3621 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -833,6 +833,50 @@ void __put_mtd_device(struct mtd_info *mtd)
}
EXPORT_SYMBOL_GPL(__put_mtd_device);

+static int nand_ecclayout_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_ecclayout *layout = mtd->ecclayout;
+
+ if (!layout)
+ return -ENOTSUPP;
+
+ if (eccbyte >= layout->eccbytes)
+ return -ERANGE;
+
+ return layout->eccpos[eccbyte];
+}
+
+static int nand_ecclayout_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_ecclayout *layout = mtd->ecclayout;
+
+ if (!layout)
+ return -ENOTSUPP;
+
+ if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE)
+ return -ERANGE;
+
+ *oobfree = layout->oobfree[section];
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops nand_ecclayout_ops = {
+ .eccpos = nand_ecclayout_eccpos,
+ .oobfree = nand_ecclayout_oobfree,
+};
+
+void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout)
+{
+ if (!mtd || !ecclayout)
+ return;
+
+ mtd->ecclayout = ecclayout;
+ mtd_set_ooblayout(mtd, &nand_ecclayout_ops);
+}
+EXPORT_SYMBOL_GPL(mtd_set_ecclayout);
+
/*
* Erase is an asynchronous operation. Device drivers are supposed
* to call instr->callback() whenever the operation completes, even
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 244faa8..2b5c8ca 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -320,6 +320,26 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
return res;
}

+static int part_ooblayout_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct mtd_part *part = mtd_to_part(mtd);
+
+ return mtd_eccpos(part->master, eccbyte);
+}
+
+static int part_ooblayout_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct mtd_part *part = mtd_to_part(mtd);
+
+ return mtd_oobfree(part->master, section, oobfree);
+}
+
+static const struct mtd_ooblayout_ops part_ooblayout_ops = {
+ .eccpos = part_ooblayout_eccpos,
+ .oobfree = part_ooblayout_oobfree,
+};
+
static inline void free_partition(struct mtd_part *p)
{
kfree(p->mtd.name);
@@ -536,7 +556,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
part->name);
}

- mtd_set_ecclayout(&slave->mtd, master->ecclayout);
+ mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
slave->mtd.ecc_step_size = master->ecc_step_size;
slave->mtd.ecc_strength = master->ecc_strength;
slave->mtd.bitflip_threshold = master->bitflip_threshold;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 80e32fa..9c3699b 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -101,6 +101,9 @@ struct mtd_oob_ops {
* similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
* for export to user-space via the ECCGETLAYOUT ioctl.
* nand_ecclayout should be expandable in the future simply by the above macros.
+ *
+ * This structure is now deprecated, you should use struct nand_ecclayout_ops
+ * to describe your OOB layout.
*/
struct nand_ecclayout {
__u32 eccbytes;
@@ -108,6 +111,20 @@ struct nand_ecclayout {
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
};

+/**
+ * struct mtd_ooblayout_ops - NAND OOB layout operations.
+ *
+ * @eccpos: function returning the position of an ECC byte. Should return
+ * -ERANGE if %eccbyte exceed the number of ECC bytes.
+ * @oobfree: function returning an oobfree section. Should return -ERANGE
+ * if %section exceed the total number of oobfree sections.
+ */
+struct mtd_ooblayout_ops {
+ int (*eccpos)(struct mtd_info *mtd, int eccbyte);
+ int (*oobfree)(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree);
+};
+
struct module; /* only needed for owner field in mtd_info */

struct mtd_info {
@@ -166,9 +183,12 @@ struct mtd_info {
const char *name;
int index;

- /* ECC layout structure pointer - read only! */
+ /* [Deprecated] ECC layout structure pointer - read only! */
struct nand_ecclayout *ecclayout;

+ /* OOB layout description */
+ const struct mtd_ooblayout_ops *ooblayout;
+
/* the ecc step size. */
unsigned int ecc_step_size;

@@ -253,21 +273,20 @@ struct mtd_info {
int usecount;
};

-static inline void mtd_set_ecclayout(struct mtd_info *mtd,
- struct nand_ecclayout *ecclayout)
+static inline void mtd_set_ooblayout(struct mtd_info *mtd,
+ const struct mtd_ooblayout_ops *ooblayout)
{
- mtd->ecclayout = ecclayout;
+ mtd->ooblayout = ooblayout;
}

+void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout);
+
static inline int mtd_eccpos(struct mtd_info *mtd, int eccbyte)
{
- if (!mtd->ecclayout)
+ if (!mtd->ooblayout || !mtd->ooblayout->eccpos)
return -ENOTSUPP;

- if (eccbyte >= mtd->ecclayout->eccbytes)
- return -ERANGE;
-
- return mtd->ecclayout->eccpos[eccbyte];
+ return mtd->ooblayout->eccpos(mtd, eccbyte);
}

static inline int mtd_oobfree(struct mtd_info *mtd, int section,
@@ -275,20 +294,20 @@ static inline int mtd_oobfree(struct mtd_info *mtd, int section,
{
memset(oobfree, 0, sizeof(*oobfree));

- if (!mtd->ecclayout)
+ if (!mtd->ooblayout || !mtd->ooblayout->oobfree)
return -ENOTSUPP;

- if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE)
- return -ERANGE;
-
- *oobfree = mtd->ecclayout->oobfree[section];
-
- return 0;
+ return mtd->ooblayout->oobfree(mtd, section, oobfree);
}

static inline int mtd_eccbytes(struct mtd_info *mtd)
{
- return mtd->ecclayout ? mtd->ecclayout->eccbytes : 0;
+ int eccbytes;
+
+ for (eccbytes = 0; mtd_eccpos(mtd, eccbytes) >= 0; eccbytes++)
+ ;
+
+ return eccbytes;
}

static inline void mtd_set_of_node(struct mtd_info *mtd,
--
2.1.4

2015-12-07 22:27:34

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 16/23] mtd: docg3: switch to mtd_ooblayout_ops

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/devices/docg3.c | 34 +++++++++++++++++++++++++++++-----
1 file changed, 29 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 6b516e1..7463dd8 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -73,10 +73,34 @@ MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, "
* @eccpos: ecc positions (byte 7 is Hamming ECC, byte 8-14 are BCH ECC)
* @oobfree: free pageinfo bytes (byte 0 until byte 6, byte 15
*/
-static struct nand_ecclayout docg3_oobinfo = {
- .eccbytes = 8,
- .eccpos = {7, 8, 9, 10, 11, 12, 13, 14},
- .oobfree = {{0, 7}, {15, 1} },
+static int docg3_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte >= 8)
+ return -ERANGE;
+
+ return eccbyte + 7;
+}
+
+static int docg3_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section > 1)
+ return -ERANGE;
+
+ if (!section) {
+ oobfree->offset = 0;
+ oobfree->length = 7;
+ } else {
+ oobfree->offset = 15;
+ oobfree->length = 1;
+ }
+
+ return 0;
+}
+
+static const struct nand_ooblayout_ops nand_ooblayout_docg3_ops = {
+ .eccpos = docg3_eccpos,
+ .oobfree = docg3_oobfree,
};

static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
@@ -1857,7 +1881,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
mtd->_read_oob = doc_read_oob;
mtd->_write_oob = doc_write_oob;
mtd->_block_isbad = doc_block_isbad;
- mtd_set_ecclayout(mtd, &docg3_oobinfo);
+ mtd_set_ooblayout_ops(mtd, &nand_ooblayout_docg3_ops);
mtd->oobavail = 8;
mtd->ecc_strength = DOC_ECC_BCH_T;

--
2.1.4

2015-12-07 22:30:28

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 17/23] mtd: nand: implement the default mtd_ooblayout_ops

Replace the default nand_ecclayout definitions for large and small page
devices with the equivalent mtd_ooblayout_ops.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/nand/nand_base.c | 138 +++++++++++++++++++++++++++----------------
include/linux/mtd/nand.h | 3 +
2 files changed, 90 insertions(+), 51 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 2b334cf..6440c5d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -48,50 +48,6 @@
#include <linux/mtd/partitions.h>
#include <linux/of_mtd.h>

-/* Define default oob placement schemes for large and small page devices */
-static struct nand_ecclayout nand_oob_8 = {
- .eccbytes = 3,
- .eccpos = {0, 1, 2},
- .oobfree = {
- {.offset = 3,
- .length = 2},
- {.offset = 6,
- .length = 2} }
-};
-
-static struct nand_ecclayout nand_oob_16 = {
- .eccbytes = 6,
- .eccpos = {0, 1, 2, 3, 6, 7},
- .oobfree = {
- {.offset = 8,
- . length = 8} }
-};
-
-static struct nand_ecclayout nand_oob_64 = {
- .eccbytes = 24,
- .eccpos = {
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63},
- .oobfree = {
- {.offset = 2,
- .length = 38} }
-};
-
-static struct nand_ecclayout nand_oob_128 = {
- .eccbytes = 48,
- .eccpos = {
- 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119,
- 120, 121, 122, 123, 124, 125, 126, 127},
- .oobfree = {
- {.offset = 2,
- .length = 78} }
-};
-
static int nand_get_device(struct mtd_info *mtd, int new_state);

static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
@@ -103,6 +59,83 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
*/
DEFINE_LED_TRIGGER(nand_led_trigger);

+/* Define default oob placement schemes for large and small page devices */
+static int nand_ooblayout_eccpos_sp(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+ if (eccbyte >= ecc->bytes * ecc->steps)
+ return -ERANGE;
+
+ if (eccbyte < 4)
+ return eccbyte;
+
+ return eccbyte + 2;
+}
+
+static int nand_ooblayout_oobfree_sp(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section > 1)
+ return -ERANGE;
+
+ if (mtd->oobsize == 16) {
+ if (section)
+ return -ERANGE;
+
+ oobfree->length = 8;
+ oobfree->offset = 8;
+ } else {
+ oobfree->length = 2;
+ if (!section)
+ oobfree->offset = 3;
+ else
+ oobfree->offset = 6;
+ }
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
+ .eccpos = nand_ooblayout_eccpos_sp,
+ .oobfree = nand_ooblayout_oobfree_sp,
+};
+EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops);
+
+static int nand_ooblayout_eccpos_lp(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int eccbytes = ecc->bytes * ecc->steps;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return mtd->oobsize - eccbytes + eccbyte;
+}
+
+static int nand_ooblayout_oobfree_lp(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+ if (section)
+ return -ERANGE;
+
+ oobfree->length = mtd->oobsize - (ecc->bytes * ecc->steps) - 2;
+ oobfree->offset = 2;
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
+ .eccpos = nand_ooblayout_eccpos_lp,
+ .oobfree = nand_ooblayout_oobfree_lp,
+};
+EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
+
static int check_offs_len(struct mtd_info *mtd,
loff_t ofs, uint64_t len)
{
@@ -4115,21 +4148,24 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->oob_poi = chip->buffers->databuf + mtd->writesize;

/*
+ * Set the provided ECC layout. If ecc->layout is NULL, the MTD core
+ * will just leave mtd->ooblayout to NULL, if it's not NULL, it will
+ * set ->ooblayout to the default ecclayout wrapper.
+ */
+ mtd_set_ecclayout(mtd, ecc->layout);
+
+ /*
* If no default placement scheme is given, select an appropriate one.
*/
- if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
+ if (!mtd->ooblayout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
switch (mtd->oobsize) {
case 8:
- ecc->layout = &nand_oob_8;
- break;
case 16:
- ecc->layout = &nand_oob_16;
+ mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
break;
case 64:
- ecc->layout = &nand_oob_64;
- break;
case 128:
- ecc->layout = &nand_oob_128;
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
break;
default:
pr_warn("No oob scheme defined for oobsize %d\n",
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index cbedcb0..9ba9daba 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -719,6 +719,9 @@ struct nand_chip {
void *priv;
};

+extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
+extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops;
+
static inline void nand_set_flash_node(struct nand_chip *chip,
struct device_node *np)
{
--
2.1.4

2015-12-07 22:29:19

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 18/23] mtd: nand: bch: switch to nand_ecclayout_pos

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/nand/nand_bch.c | 33 +++++++++++----------------------
1 file changed, 11 insertions(+), 22 deletions(-)

diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index 9cff544..2937b49 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -32,13 +32,11 @@
/**
* struct nand_bch_control - private NAND BCH control structure
* @bch: BCH control structure
- * @ecclayout: private ecc layout for this BCH configuration
* @errloc: error location array
* @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
*/
struct nand_bch_control {
struct bch_control *bch;
- struct nand_ecclayout ecclayout;
unsigned int *errloc;
unsigned char *eccmask;
};
@@ -124,7 +122,6 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
{
struct nand_chip *nand = mtd_to_nand(mtd);
unsigned int m, t, eccsteps, i;
- struct nand_ecclayout *layout = nand->ecc.layout;
struct nand_bch_control *nbc = NULL;
unsigned char *erased_page;
unsigned int eccsize = nand->ecc.size;
@@ -161,8 +158,17 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)

eccsteps = mtd->writesize/eccsize;

+ /*
+ * Rely on the default ecclayout to ooblayout wrapper provided by MTD
+ * core if ecc.layout is not NULL.
+ * FIXME: this should be removed when all callers have moved to the
+ * mtd_ooblayout_ops approach.
+ */
+ if (nand->ecc.layout)
+ mtd_set_ecclayout(mtd, nand->ecc.layout);
+
/* if no ecc placement scheme was provided, build one */
- if (!layout) {
+ if (!mtd->ooblayout) {

/* handle large page devices only */
if (mtd->oobsize < 64) {
@@ -171,24 +177,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
goto fail;
}

- layout = &nbc->ecclayout;
- layout->eccbytes = eccsteps*eccbytes;
-
- /* reserve 2 bytes for bad block marker */
- if (layout->eccbytes+2 > mtd->oobsize) {
- printk(KERN_WARNING "no suitable oob scheme available "
- "for oobsize %d eccbytes %u\n", mtd->oobsize,
- eccbytes);
- goto fail;
- }
- /* put ecc bytes at oob tail */
- for (i = 0; i < layout->eccbytes; i++)
- layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
-
- layout->oobfree[0].offset = 2;
- layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
-
- nand->ecc.layout = layout;
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
}

/* sanity checks */
--
2.1.4

2015-12-07 22:27:48

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 19/23] mtd: nand: switch all drivers to mtd_ooblayout_ops

Implementing the mtd_ooblayout_ops interface is the new way of exposing
ECC/OOB layout to MTD users. Modify all NAND drivers to switch to this
approach.

Signed-off-by: Boris Brezillon <[email protected]>

---
This commit is a collection of commits that have been squashed to into
a single one to limit the size of the patchset. If you want to have
separate commit for each of the NAND drivers you can have a look at
this branch [1].

[1]https://github.com/bbrezillon/linux-sunxi/commits/nand/ecclayout2
---
arch/arm/mach-pxa/spitz.c | 41 +++-
arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 2 +-
arch/mips/jz4740/board-qi_lb60.c | 83 ++++---
drivers/mtd/nand/atmel_nand.c | 81 +++----
drivers/mtd/nand/bf5xx_nand.c | 47 ++--
drivers/mtd/nand/brcmnand/brcmnand.c | 255 ++++++++++++--------
drivers/mtd/nand/cafe_nand.c | 42 +++-
drivers/mtd/nand/davinci_nand.c | 114 ++++-----
drivers/mtd/nand/denali.c | 48 ++--
drivers/mtd/nand/diskonchip.c | 34 ++-
drivers/mtd/nand/docg4.c | 29 ++-
drivers/mtd/nand/fsl_elbc_nand.c | 79 ++++---
drivers/mtd/nand/fsl_ifc_nand.c | 224 +++++-------------
drivers/mtd/nand/fsmc_nand.c | 294 +++++++-----------------
drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 48 +++-
drivers/mtd/nand/hisi504_nand.c | 26 ++-
drivers/mtd/nand/jz4740_nand.c | 2 +-
drivers/mtd/nand/lpc32xx_mlc.c | 49 ++--
drivers/mtd/nand/lpc32xx_slc.c | 37 ++-
drivers/mtd/nand/mxc_nand.c | 206 ++++++++---------
drivers/mtd/nand/omap2.c | 184 ++++++++-------
drivers/mtd/nand/pxa3xx_nand.c | 101 ++++----
drivers/mtd/nand/s3c2410.c | 28 ++-
drivers/mtd/nand/sh_flctl.c | 80 +++++--
drivers/mtd/nand/sharpsl.c | 2 +-
drivers/mtd/nand/sm_common.c | 88 +++++--
drivers/mtd/nand/sunxi_nand.c | 112 ++++-----
drivers/mtd/nand/vf610_nfc.c | 34 +--
include/linux/mtd/sharpsl.h | 2 +-
29 files changed, 1226 insertions(+), 1146 deletions(-)

diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index f4e2e27..13ed4e3 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -763,14 +763,35 @@ static struct nand_bbt_descr spitz_nand_bbt = {
.pattern = scan_ff_pattern
};

-static struct nand_ecclayout akita_oobinfo = {
- .oobfree = { {0x08, 0x09} },
- .eccbytes = 24,
- .eccpos = {
- 0x05, 0x01, 0x02, 0x03, 0x06, 0x07, 0x15, 0x11,
- 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
- 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37,
- },
+static int akita_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ static int eccpos[] = {
+ 0x05, 0x01, 0x02, 0x03, 0x06, 0x07, 0x15, 0x11,
+ 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
+ 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37,
+ };
+
+ if (eccbyte >= ARRAY_SIZE(eccpos))
+ return -ERANGE;
+
+ return eccpos[eccbyte];
+}
+
+static int akita_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section)
+ return -ERANGE;
+
+ oobfree->offset = 8;
+ oobfree->length = 9;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops akita_ooblayout_ops = {
+ .eccpos = akita_eccpos,
+ .oobfree = akita_oobfree,
};

static struct sharpsl_nand_platform_data spitz_nand_pdata = {
@@ -804,11 +825,11 @@ static void __init spitz_nand_init(void)
} else if (machine_is_akita()) {
spitz_nand_partitions[1].size = 58 * 1024 * 1024;
spitz_nand_bbt.len = 1;
- spitz_nand_pdata.ecc_layout = &akita_oobinfo;
+ spitz_nand_pdata.ecc_layout = &akita_ooblayout_ops;
} else if (machine_is_borzoi()) {
spitz_nand_partitions[1].size = 32 * 1024 * 1024;
spitz_nand_bbt.len = 1;
- spitz_nand_pdata.ecc_layout = &akita_oobinfo;
+ spitz_nand_pdata.ecc_layout = &akita_ooblayout_ops;
}

platform_device_register(&spitz_nand_device);
diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
index 398733e..7f7b0fc 100644
--- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
+++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
@@ -27,7 +27,7 @@ struct jz_nand_platform_data {

unsigned char banks[JZ_NAND_NUM_BANKS];

- void (*ident_callback)(struct platform_device *, struct nand_chip *,
+ void (*ident_callback)(struct platform_device *, struct mtd_info *,
struct mtd_partition **, int *num_partitions);
};

diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 934b15b..951621a 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -50,20 +50,6 @@ static bool is_avt2;
#define QI_LB60_GPIO_KEYIN8 JZ_GPIO_PORTD(26)

/* NAND */
-static struct nand_ecclayout qi_lb60_ecclayout_1gb = {
- .eccbytes = 36,
- .eccpos = {
- 6, 7, 8, 9, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, 32, 33, 34, 35, 36, 37,
- 38, 39, 40, 41
- },
- .oobfree = {
- { .offset = 2, .length = 4 },
- { .offset = 42, .length = 22 }
- },
-};

/* Early prototypes of the QI LB60 had only 1GB of NAND.
* In order to support these devices as well the partition and ecc layout is
@@ -86,25 +72,6 @@ static struct mtd_partition qi_lb60_partitions_1gb[] = {
},
};

-static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
- .eccbytes = 72,
- .eccpos = {
- 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35,
- 36, 37, 38, 39, 40, 41, 42, 43,
- 44, 45, 46, 47, 48, 49, 50, 51,
- 52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, 62, 63, 64, 65, 66, 67,
- 68, 69, 70, 71, 72, 73, 74, 75,
- 76, 77, 78, 79, 80, 81, 82, 83
- },
- .oobfree = {
- { .offset = 2, .length = 10 },
- { .offset = 84, .length = 44 },
- },
-};
-
static struct mtd_partition qi_lb60_partitions_2gb[] = {
{
.name = "NAND BOOT partition",
@@ -123,19 +90,63 @@ static struct mtd_partition qi_lb60_partitions_2gb[] = {
},
};

+static int qi_lb60_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ int eccbytes = 36, eccoff = 6;
+
+ if (mtd->oobsize == 128) {
+ eccbytes *= 2;
+ eccoff *= 2;
+ }
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return eccoff + eccbyte;
+}
+
+static int qi_lb60_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ int eccbytes = 36, eccoff = 6;
+
+ if (section > 1)
+ return -ERANGE;
+
+ if (mtd->oobsize == 128) {
+ eccbytes *= 2;
+ eccoff *= 2;
+ }
+
+ if (!section) {
+ oobfree->offset = 2;
+ oobfree->length = eccoff - 2;
+ } else {
+ oobfree->offset = eccoff + eccbytes;
+ oobfree->length = mtd->oobsize - oobfree->offset;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops qi_lb60_ooblayout_ops = {
+ .eccpos = qi_lb60_eccpos,
+ .oobfree = qi_lb60_oobfree,
+};
+
static void qi_lb60_nand_ident(struct platform_device *pdev,
- struct nand_chip *chip, struct mtd_partition **partitions,
+ struct mtd_info *mtd, struct mtd_partition **partitions,
int *num_partitions)
{
if (chip->page_shift == 12) {
- chip->ecc.layout = &qi_lb60_ecclayout_2gb;
*partitions = qi_lb60_partitions_2gb;
*num_partitions = ARRAY_SIZE(qi_lb60_partitions_2gb);
} else {
- chip->ecc.layout = &qi_lb60_ecclayout_1gb;
*partitions = qi_lb60_partitions_1gb;
*num_partitions = ARRAY_SIZE(qi_lb60_partitions_1gb);
}
+
+ mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops);
}

static struct jz_nand_platform_data qi_lb60_nand_pdata = {
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index da16b1a..e67a502 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -67,30 +67,40 @@ struct atmel_nand_caps {
bool pmecc_correct_erase_page;
};

-/* oob layout for large page size
+/*
+ * oob layout for large page size
* bad block info is on bytes 0 and 1
* the bytes have to be consecutives to avoid
* several NAND_CMD_RNDOUT during read
- */
-static struct nand_ecclayout atmel_oobinfo_large = {
- .eccbytes = 4,
- .eccpos = {60, 61, 62, 63},
- .oobfree = {
- {2, 58}
- },
-};
-
-/* oob layout for small page size
+ *
+ * oob layout for small page size
* bad block info is on bytes 4 and 5
* the bytes have to be consecutives to avoid
* several NAND_CMD_RNDOUT during read
*/
-static struct nand_ecclayout atmel_oobinfo_small = {
- .eccbytes = 4,
- .eccpos = {0, 1, 2, 3},
- .oobfree = {
- {6, 10}
- },
+static int atmel_eccpos_sp(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte >= 4)
+ return -ERANGE;
+
+ return eccbyte;
+}
+
+static int atmel_oobfree_sp(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section)
+ return -ERANGE;
+
+ oobfree->offset = 6;
+ oobfree->length = mtd->oobsize - oobfree->offset;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops atmel_ooblayout_sp_ops = {
+ .eccpos = atmel_eccpos_sp,
+ .oobfree = atmel_oobfree_sp,
};

struct atmel_nfc {
@@ -157,8 +167,6 @@ struct atmel_nand_host {
int *pmecc_delta;
};

-static struct nand_ecclayout atmel_pmecc_oobinfo;
-
/*
* Enable NAND.
*/
@@ -474,22 +482,6 @@ static int pmecc_get_ecc_bytes(int cap, int sector_size)
return (m * cap + 7) / 8;
}

-static void pmecc_config_ecc_layout(struct nand_ecclayout *layout,
- int oobsize, int ecc_len)
-{
- int i;
-
- layout->eccbytes = ecc_len;
-
- /* ECC will occupy the last ecc_len bytes continuously */
- for (i = 0; i < ecc_len; i++)
- layout->eccpos[i] = oobsize - ecc_len + i;
-
- layout->oobfree[0].offset = PMECC_OOB_RESERVED_BYTES;
- layout->oobfree[0].length =
- oobsize - ecc_len - layout->oobfree[0].offset;
-}
-
static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
{
int table_size;
@@ -993,8 +985,8 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd->priv;
struct atmel_nand_host *host = nand_chip->priv;
+ int eccbytes = nand_chip->ecc.bytes * nand_chip->ecc.steps;
uint32_t val = 0;
- struct nand_ecclayout *ecc_layout;

pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
@@ -1041,11 +1033,9 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
| PMECC_CFG_AUTO_DISABLE);
pmecc_writel(host->ecc, CFG, val);

- ecc_layout = nand_chip->ecc.layout;
pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
pmecc_writel(host->ecc, SADDR, mtd_eccpos(mtd, 0));
- pmecc_writel(host->ecc, EADDR,
- mtd_eccpos(mtd, ecc_layout->eccbytes - 1));
+ pmecc_writel(host->ecc, EADDR, mtd_eccpos(mtd, eccbytes - 1));
/* See datasheet about PMECC Clock Control Register */
pmecc_writel(host->ecc, CLK, 2);
pmecc_writel(host->ecc, IDR, 0xff);
@@ -1260,11 +1250,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
err_no = -EINVAL;
goto err;
}
- pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
- mtd->oobsize,
- nand_chip->ecc.total);

- nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
break;
default:
dev_warn(host->dev,
@@ -1607,19 +1594,19 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev,
/* set ECC page size and oob layout */
switch (mtd->writesize) {
case 512:
- nand_chip->ecc.layout = &atmel_oobinfo_small;
+ mtd_set_ooblayout(mtd, &atmel_ooblayout_sp_ops);
ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
break;
case 1024:
- nand_chip->ecc.layout = &atmel_oobinfo_large;
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
break;
case 2048:
- nand_chip->ecc.layout = &atmel_oobinfo_large;
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
break;
case 4096:
- nand_chip->ecc.layout = &atmel_oobinfo_large;
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
break;
default:
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 61bd216..c0bbcd6 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -109,28 +109,29 @@ static const unsigned short bfin_nfc_pin_req[] =
0};

#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
-static struct nand_ecclayout bootrom_ecclayout = {
- .eccbytes = 24,
- .eccpos = {
- 0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2,
- 0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2,
- 0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2,
- 0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2,
- 0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2,
- 0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2,
- 0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2,
- 0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2
- },
- .oobfree = {
- { 0x8 * 0 + 3, 5 },
- { 0x8 * 1 + 3, 5 },
- { 0x8 * 2 + 3, 5 },
- { 0x8 * 3 + 3, 5 },
- { 0x8 * 4 + 3, 5 },
- { 0x8 * 5 + 3, 5 },
- { 0x8 * 6 + 3, 5 },
- { 0x8 * 7 + 3, 5 },
- }
+static int bootrom_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte >= 24)
+ return -ERANGE;
+
+ return ((eccbyte / 3) * 8) + (eccbyte % 3);
+}
+
+static int bootrom_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section > 7)
+ return -ERANGE;
+
+ oobfree->offset = section * 8;
+ oobfree->length = 5;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops bootrom_ooblayout_ops = {
+ .eccpos = bootrom_eccpos,
+ .oobfree = bootrom_oobfree,
};
#endif

@@ -793,7 +794,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
/* setup hardware ECC data struct */
if (hardware_ecc) {
#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
- chip->ecc.layout = &bootrom_ecclayout;
+ mtd_set_ooblayout(mtd, &bootrom_ooblayout_ops);
#endif
chip->read_buf = bf5xx_nand_dma_read_buf;
chip->write_buf = bf5xx_nand_dma_write_buf;
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index a906ec2..5815afd 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -746,126 +746,179 @@ static inline bool is_hamming_ecc(struct brcmnand_cfg *cfg)
}

/*
- * Returns a nand_ecclayout strucutre for the given layout/configuration.
- * Returns NULL on failure.
+ * Set mtd->ooblayout to the appropriate mtd_ooblayout_ops given
+ * the layout/configuration.
+ * Returns -ERRCODE on failure.
*/
-static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
- struct brcmnand_host *host)
+static int brcmnand_hamming_eccpos(struct mtd_info *mtd, int eccbyte)
{
+ struct nand_chip *chip = mtd->priv;
+ struct brcmnand_host *host = chip->priv;
struct brcmnand_cfg *cfg = &host->hwcfg;
- int i, j;
- struct nand_ecclayout *layout;
- int req;
- int sectors;
- int sas;
- int idx1, idx2;
-
- layout = devm_kzalloc(&host->pdev->dev, sizeof(*layout), GFP_KERNEL);
- if (!layout)
- return NULL;
-
- sectors = cfg->page_size / (512 << cfg->sector_size_1k);
- sas = cfg->spare_area_size << cfg->sector_size_1k;
-
- /* Hamming */
- if (is_hamming_ecc(cfg)) {
- for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) {
- /* First sector of each page may have BBI */
- if (i == 0) {
- layout->oobfree[idx2].offset = i * sas + 1;
- /* Small-page NAND use byte 6 for BBI */
- if (cfg->page_size == 512)
- layout->oobfree[idx2].offset--;
- layout->oobfree[idx2].length = 5;
- } else {
- layout->oobfree[idx2].offset = i * sas;
- layout->oobfree[idx2].length = 6;
- }
- idx2++;
- layout->eccpos[idx1++] = i * sas + 6;
- layout->eccpos[idx1++] = i * sas + 7;
- layout->eccpos[idx1++] = i * sas + 8;
- layout->oobfree[idx2].offset = i * sas + 9;
- layout->oobfree[idx2].length = 7;
- idx2++;
- /* Leave zero-terminated entry for OOBFREE */
- if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE ||
- idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
- break;
+ int sas = cfg->spare_area_size << cfg->sector_size_1k;
+ int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+ int sector = eccbyte / 3;
+
+ if (sector >= sectors)
+ return -ERANGE;
+
+ return (sector * sas) + (eccbyte % 3) + 6;
+}
+
+static int brcmnand_hamming_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct brcmnand_host *host = chip->priv;
+ struct brcmnand_cfg *cfg = &host->hwcfg;
+ int sas = cfg->spare_area_size << cfg->sector_size_1k;
+ int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+
+ if (section >= sectors * 2)
+ return -ERANGE;
+
+ oobfree->offset = (section / 2) * sas;
+
+ if (section & 1) {
+ oobfree->offset += 9;
+ oobfree->length = 7;
+ } else {
+ oobfree->length = 6;
+
+ /* First sector of each page may have BBI */
+ if (!section) {
+ /*
+ * Small-page NAND use byte 6 for BBI while large-page
+ * NAND use byte 0.
+ */
+ if (cfg->page_size > 512)
+ oobfree->offset++;
+ oobfree->length--;
}
- goto out;
}

- /*
- * CONTROLLER_VERSION:
- * < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
- * >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
- * But we will just be conservative.
- */
- req = DIV_ROUND_UP(ecc_level * 14, 8);
- if (req >= sas) {
- dev_err(&host->pdev->dev,
- "error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
- req, sas);
- return NULL;
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
+ .eccpos = brcmnand_hamming_eccpos,
+ .oobfree = brcmnand_hamming_oobfree,
+};
+
+static int brcmnand_bch_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct brcmnand_host *host = chip->priv;
+ struct brcmnand_cfg *cfg = &host->hwcfg;
+ int sas = cfg->spare_area_size << cfg->sector_size_1k;
+ int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+ int sector = eccbyte / chip->ecc.bytes;
+
+ if (sector >= sectors)
+ return -ERANGE;
+
+ return (sector * (sas + 1)) - chip->ecc.bytes +
+ (eccbyte % chip->ecc.bytes);
+}
+
+static int brcmnand_bch_oobfree_lp(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct brcmnand_host *host = chip->priv;
+ struct brcmnand_cfg *cfg = &host->hwcfg;
+ int sas = cfg->spare_area_size << cfg->sector_size_1k;
+ int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+
+ if (section >= sectors)
+ return -ERANGE;
+
+ if (sas <= chip->ecc.bytes)
+ return 0;
+
+ oobfree->offset = section * sas;
+ oobfree->length = sas - chip->ecc.bytes;
+
+ if (!section) {
+ oobfree->offset++;
+ oobfree->length--;
}

- layout->eccbytes = req * sectors;
- for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) {
- for (j = sas - req; j < sas && idx1 <
- MTD_MAX_ECCPOS_ENTRIES_LARGE; j++, idx1++)
- layout->eccpos[idx1] = i * sas + j;
+ return 0;
+}

- /* First sector of each page may have BBI */
- if (i == 0) {
- if (cfg->page_size == 512 && (sas - req >= 6)) {
- /* Small-page NAND use byte 6 for BBI */
- layout->oobfree[idx2].offset = 0;
- layout->oobfree[idx2].length = 5;
- idx2++;
- if (sas - req > 6) {
- layout->oobfree[idx2].offset = 6;
- layout->oobfree[idx2].length =
- sas - req - 6;
- idx2++;
- }
- } else if (sas > req + 1) {
- layout->oobfree[idx2].offset = i * sas + 1;
- layout->oobfree[idx2].length = sas - req - 1;
- idx2++;
- }
- } else if (sas > req) {
- layout->oobfree[idx2].offset = i * sas;
- layout->oobfree[idx2].length = sas - req;
- idx2++;
- }
- /* Leave zero-terminated entry for OOBFREE */
- if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE ||
- idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
- break;
+static int brcmnand_bch_oobfree_sp(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct brcmnand_host *host = chip->priv;
+ struct brcmnand_cfg *cfg = &host->hwcfg;
+ int sas = cfg->spare_area_size << cfg->sector_size_1k;
+
+ if (section > 1 || sas - chip->ecc.bytes < 6 ||
+ (section && sas - chip->ecc.bytes == 6))
+ return -ERANGE;
+
+ if (!section) {
+ oobfree->offset = 0;
+ oobfree->length = 5;
+ } else {
+ oobfree->offset = 6;
+ oobfree->length = sas - chip->ecc.bytes - 6;
}
-out:
- return layout;
+
+ return 0;
}

-static struct nand_ecclayout *brcmstb_choose_ecc_layout(
- struct brcmnand_host *host)
+static const struct mtd_ooblayout_ops brcmnand_bch_lp_ooblayout_ops = {
+ .eccpos = brcmnand_bch_eccpos,
+ .oobfree = brcmnand_bch_oobfree_lp,
+};
+
+static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
+ .eccpos = brcmnand_bch_eccpos,
+ .oobfree = brcmnand_bch_oobfree_sp,
+};
+
+static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
{
- struct nand_ecclayout *layout;
struct brcmnand_cfg *p = &host->hwcfg;
+ struct mtd_info *mtd = &host->mtd;
+ struct nand_ecc_ctrl *ecc = &host->chip.ecc;
unsigned int ecc_level = p->ecc_level;
+ int sas = p->spare_area_size << p->sector_size_1k;
+ int sectors = p->page_size / (512 << p->sector_size_1k);

if (p->sector_size_1k)
ecc_level <<= 1;

- layout = brcmnand_create_layout(ecc_level, host);
- if (!layout) {
+ if (is_hamming_ecc(p)) {
+ ecc->bytes = 3 * sectors;
+ mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
+ return 0;
+ } else {
+ /*
+ * CONTROLLER_VERSION:
+ * < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
+ * >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
+ * But we will just be conservative.
+ */
+ ecc->bytes = DIV_ROUND_UP(ecc_level * 14, 8);
+
+ if (p->page_size == 512)
+ mtd_set_ooblayout(mtd, &brcmnand_bch_sp_ooblayout_ops);
+ else
+ mtd_set_ooblayout(mtd, &brcmnand_bch_lp_ooblayout_ops);
+ }
+
+ if (ecc->bytes >= sas) {
dev_err(&host->pdev->dev,
- "no proper ecc_layout for this NAND cfg\n");
- return NULL;
+ "error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
+ ecc->bytes, sas);
+ return -EINVAL;
}

- return layout;
+ return 0;
}

static void brcmnand_wp(struct mtd_info *mtd, int wp)
@@ -1976,9 +2029,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
/* only use our internal HW threshold */
mtd->bitflip_threshold = 1;

- chip->ecc.layout = brcmstb_choose_ecc_layout(host);
- if (!chip->ecc.layout)
- return -ENXIO;
+ ret = brcmstb_choose_ecc_layout(host);
+ if (ret)
+ return ret;

if (nand_scan_tail(mtd))
return -ENXIO;
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index cce3ac4..39b2dcd 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -459,10 +459,35 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return max_bitflips;
}

-static struct nand_ecclayout cafe_oobinfo_2048 = {
- .eccbytes = 14,
- .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
- .oobfree = {{14, 50}}
+static int cafe_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd->priv;
+ int eccbytes = chip->ecc.steps * chip->ecc.bytes;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return eccbyte;
+}
+
+static int cafe_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd->priv;
+ int eccbytes = chip->ecc.steps * chip->ecc.bytes;
+
+ if (section)
+ return -ERANGE;
+
+ oobfree->offset = eccbytes;
+ oobfree->length = mtd->oobsize - eccbytes;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops cafe_ooblayout_ops = {
+ .eccpos = cafe_eccpos,
+ .oobfree = cafe_oobfree,
};

/* Ick. The BBT code really ought to be able to work this bit out
@@ -494,12 +519,6 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
.pattern = cafe_mirror_pattern_2048
};

-static struct nand_ecclayout cafe_oobinfo_512 = {
- .eccbytes = 14,
- .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
- .oobfree = {{14, 2}}
-};
-
static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION,
@@ -744,12 +763,11 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe->ctl2 |= 1<<29; /* 2KiB page size */

/* Set up ECC according to the type of chip we found */
+ mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
if (mtd->writesize == 2048) {
- cafe->nand.ecc.layout = &cafe_oobinfo_2048;
cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
} else if (mtd->writesize == 512) {
- cafe->nand.ecc.layout = &cafe_oobinfo_512;
cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
} else {
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 8e351af..116ee76 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -55,7 +55,6 @@
struct davinci_nand_info {
struct mtd_info mtd;
struct nand_chip chip;
- struct nand_ecclayout ecclayout;

struct device *dev;
struct clk *clk;
@@ -487,63 +486,39 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
* ten ECC bytes plus the manufacturer's bad block marker byte, and
* and not overlapping the default BBT markers.
*/
-static struct nand_ecclayout hwecc4_small = {
- .eccbytes = 10,
- .eccpos = { 0, 1, 2, 3, 4,
- /* offset 5 holds the badblock marker */
- 6, 7,
- 13, 14, 15, },
- .oobfree = {
- {.offset = 8, .length = 5, },
- {.offset = 16, },
- },
-};
+static int hwecc4_small_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte >= 10)
+ return -ERANGE;

-/* An ECC layout for using 4-bit ECC with large-page (2048bytes) flash,
- * storing ten ECC bytes plus the manufacturer's bad block marker byte,
- * and not overlapping the default BBT markers.
- */
-static struct nand_ecclayout hwecc4_2048 = {
- .eccbytes = 40,
- .eccpos = {
- /* at the end of spare sector */
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
- 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- },
- .oobfree = {
- /* 2 bytes at offset 0 hold manufacturer badblock markers */
- {.offset = 2, .length = 22, },
- /* 5 bytes at offset 8 hold BBT markers */
- /* 8 bytes at offset 16 hold JFFS2 clean markers */
- },
-};
+ if (eccbyte < 5)
+ return eccbyte;
+ else if (eccbyte < 7)
+ return eccbyte + 1;

-/*
- * An ECC layout for using 4-bit ECC with large-page (4096bytes) flash,
- * storing ten ECC bytes plus the manufacturer's bad block marker byte,
- * and not overlapping the default BBT markers.
- */
-static struct nand_ecclayout hwecc4_4096 = {
- .eccbytes = 80,
- .eccpos = {
- /* at the end of spare sector */
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
- 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
- 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
- 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
- 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
- 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
- },
- .oobfree = {
- /* 2 bytes at offset 0 hold manufacturer badblock markers */
- {.offset = 2, .length = 46, },
- /* 5 bytes at offset 8 hold BBT markers */
- /* 8 bytes at offset 16 hold JFFS2 clean markers */
- },
+ return eccbyte + 6;
+}
+
+static int hwecc4_small_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section > 1)
+ return -ERANGE;
+
+ if (!section) {
+ oobfree->offset = 8;
+ oobfree->length = 5;
+ } else {
+ oobfree->offset = 16;
+ oobfree->length = mtd->oobsize - 16;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops hwecc4_small_ooblayout_ops = {
+ .eccpos = hwecc4_small_eccpos,
+ .oobfree = hwecc4_small_oobfree,
};

#if defined(CONFIG_OF)
@@ -810,27 +785,16 @@ static int nand_davinci_probe(struct platform_device *pdev)
* table marker fits in the free bytes.
*/
if (chunks == 1) {
- info->ecclayout = hwecc4_small;
- info->ecclayout.oobfree[1].length =
- info->mtd.oobsize - 16;
- goto syndrome_done;
- }
- if (chunks == 4) {
- info->ecclayout = hwecc4_2048;
+ mtd_set_ooblayout(&info->mtd,
+ &hwecc4_small_ooblayout_ops);
+ } else if (chunks == 4 || chunks == 8) {
+ mtd_set_ooblayout(&info->mtd,
+ &nand_ooblayout_lp_ops);
info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
- goto syndrome_done;
- }
- if (chunks == 8) {
- info->ecclayout = hwecc4_4096;
- info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
- goto syndrome_done;
+ } else {
+ ret = -EIO;
+ goto err;
}
-
- ret = -EIO;
- goto err;
-
-syndrome_done:
- info->chip.ecc.layout = &info->ecclayout;
}

ret = nand_scan_tail(&info->mtd);
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 67eb2be..23086e3 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1369,13 +1369,39 @@ static void denali_hw_init(struct denali_nand_info *denali)
* correction
*/
#define ECC_8BITS 14
-static struct nand_ecclayout nand_8bit_oob = {
- .eccbytes = 14,
-};
-
#define ECC_15BITS 26
-static struct nand_ecclayout nand_15bit_oob = {
- .eccbytes = 26,
+
+static int denali_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int eccbytes = chip->ecc.bytes * chip->ecc.steps;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return eccbyte + denali->bbtskipbytes;
+}
+
+static int denali_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int eccbytes = chip->ecc.bytes * chip->ecc.steps;
+
+ if (section)
+ return -ERANGE;
+
+ oobfree->offset = eccbytes + denali->bbtskipbytes;
+ oobfree->length = mtd->oobsize - oobfree->offset;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
+ .eccpos = denali_eccpos,
+ .oobfree = denali_oobfree,
};

static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
@@ -1556,7 +1582,6 @@ int denali_init(struct denali_nand_info *denali)
ECC_SECTOR_SIZE)))) {
/* if MLC OOB size is large enough, use 15bit ECC*/
denali->nand.ecc.strength = 15;
- denali->nand.ecc.layout = &nand_15bit_oob;
denali->nand.ecc.bytes = ECC_15BITS;
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
} else if (denali->mtd.oobsize < (denali->bbtskipbytes +
@@ -1566,20 +1591,13 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
} else {
denali->nand.ecc.strength = 8;
- denali->nand.ecc.layout = &nand_8bit_oob;
denali->nand.ecc.bytes = ECC_8BITS;
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
}

+ mtd_set_ooblayout(&denali->mtd, &denali_ooblayout_ops);
denali->nand.ecc.bytes *= denali->devnum;
denali->nand.ecc.strength *= denali->devnum;
- denali->nand.ecc.layout->eccbytes *=
- denali->mtd.writesize / ECC_SECTOR_SIZE;
- denali->nand.ecc.layout->oobfree[0].offset =
- denali->bbtskipbytes + denali->nand.ecc.layout->eccbytes;
- denali->nand.ecc.layout->oobfree[0].length =
- denali->mtd.oobsize - denali->nand.ecc.layout->eccbytes -
- denali->bbtskipbytes;

/*
* Let driver know the total blocks number and how many blocks
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 0802158..7101c9a 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -993,10 +993,34 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
* safer. The only problem with it is that any code that parses oobfree must
* be able to handle out-of-order segments.
*/
-static struct nand_ecclayout doc200x_oobinfo = {
- .eccbytes = 6,
- .eccpos = {0, 1, 2, 3, 4, 5},
- .oobfree = {{8, 8}, {6, 2}}
+static int doc200x_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte > 5)
+ return -ERANGE;
+
+ return eccbyte;
+}
+
+static int doc200x_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section > 1)
+ return -ERANGE;
+
+ if (!section) {
+ oobfree->offset = 8;
+ oobfree->length = 8;
+ } else {
+ oobfree->offset = 6;
+ oobfree->length = 2;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
+ .eccpos = doc200x_eccpos,
+ .oobfree = doc200x_oobfree,
};

/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
@@ -1571,6 +1595,7 @@ static int __init doc_probe(unsigned long physadr)

mtd->priv = nand;
mtd->owner = THIS_MODULE;
+ mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);

nand->priv = doc;
nand->select_chip = doc200x_select_chip;
@@ -1582,7 +1607,6 @@ static int __init doc_probe(unsigned long physadr)
nand->ecc.calculate = doc200x_calculate_ecc;
nand->ecc.correct = doc200x_correct_data;

- nand->ecc.layout = &doc200x_oobinfo;
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
nand->ecc.size = 512;
nand->ecc.bytes = 6;
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index fdce91a..c032536 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -222,10 +222,29 @@ struct docg4_priv {
* Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
* Byte 15 (the last) is used by the driver as a "page written" flag.
*/
-static struct nand_ecclayout docg4_oobinfo = {
- .eccbytes = 9,
- .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
- .oobfree = { {.offset = 2, .length = 5} }
+static int docg4_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte > 8)
+ return -ERANGE;
+
+ return eccbyte + 7;
+}
+
+static int docg4_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section)
+ return -ERANGE;
+
+ oobfree->offset = 2;
+ oobfree->length = 5;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
+ .eccpos = docg4_eccpos,
+ .oobfree = docg4_oobfree,
};

/*
@@ -1209,6 +1228,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
mtd->writesize = DOCG4_PAGE_SIZE;
mtd->erasesize = DOCG4_BLOCK_SIZE;
mtd->oobsize = DOCG4_OOB_SIZE;
+ mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
nand->chipsize = DOCG4_CHIP_SIZE;
nand->chip_shift = DOCG4_CHIP_SHIFT;
nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
@@ -1217,7 +1237,6 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->pagemask = 0x3ffff;
nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
nand->badblockbits = 8;
- nand->ecc.layout = &docg4_oobinfo;
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
nand->ecc.size = DOCG4_PAGE_SIZE;
nand->ecc.prepad = 8;
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index bd6d493..716ecb3 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -80,32 +80,53 @@ struct fsl_elbc_fcm_ctrl {

/* These map to the positions used by the FCM hardware ECC generator */

-/* Small Page FLASH with FMR[ECCM] = 0 */
-static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
- .eccbytes = 3,
- .eccpos = {6, 7, 8},
- .oobfree = { {0, 5}, {9, 7} },
-};
+static int fsl_elbc_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_elbc_mtd *priv = chip->priv;
+ int eccbytes = chip->ecc.bytes * chip->ecc.steps;
+ int eccpos;

-/* Small Page FLASH with FMR[ECCM] = 1 */
-static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
- .eccbytes = 3,
- .eccpos = {8, 9, 10},
- .oobfree = { {0, 5}, {6, 2}, {11, 5} },
-};
+ if (eccbyte >= eccbytes)
+ return -ERANGE;

-/* Large Page FLASH with FMR[ECCM] = 0 */
-static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
- .eccbytes = 12,
- .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
- .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} },
-};
+ eccpos = ((eccbyte / chip->ecc.bytes) * 16) +
+ (eccbyte % chip->ecc.bytes) + 6;
+ if (priv->fmr & FMR_ECCM)
+ eccpos += 2;
+
+ return eccpos;
+}
+
+static int fsl_elbc_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct fsl_elbc_mtd *priv = chip->priv;

-/* Large Page FLASH with FMR[ECCM] = 1 */
-static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
- .eccbytes = 12,
- .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
- .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
+ if (section > chip->ecc.steps)
+ return -ERANGE;
+
+ if (!section) {
+ oobfree->offset = 0;
+ if (mtd->writesize > 512)
+ oobfree->offset++;
+ oobfree->length = (priv->fmr & FMR_ECCM) ? 7 : 5;
+ } else {
+ oobfree->offset = (16 * section) -
+ ((priv->fmr & FMR_ECCM) ? 5 : 7);
+ if (section < chip->ecc.steps)
+ oobfree->length = 13;
+ else
+ oobfree->length = mtd->oobsize - oobfree->offset;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
+ .eccpos = fsl_elbc_eccpos,
+ .oobfree = fsl_elbc_oobfree,
};

/*
@@ -676,14 +697,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
} else if (mtd->writesize == 2048) {
priv->page_size = 1;
setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
- /* adjust ecc setup if needed */
- if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
- BR_DECC_CHK_GEN) {
- chip->ecc.size = 512;
- chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
- &fsl_elbc_oob_lp_eccm1 :
- &fsl_elbc_oob_lp_eccm0;
- }
} else {
dev_err(priv->dev,
"fsl_elbc_init: page size %d is not supported\n",
@@ -781,9 +794,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
BR_DECC_CHK_GEN) {
chip->ecc.mode = NAND_ECC_HW;
- /* put in small page settings and adjust later if needed */
- chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
- &fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
+ mtd_set_ooblayout(&priv->mtd, &fsl_elbc_ooblayout_op);
chip->ecc.size = 512;
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 610308e..fbd2548 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -68,136 +68,6 @@ struct fsl_ifc_nand_ctrl {

static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;

-/* 512-byte page with 4-bit ECC, 8-bit */
-static struct nand_ecclayout oob_512_8bit_ecc4 = {
- .eccbytes = 8,
- .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
- .oobfree = { {0, 5}, {6, 2} },
-};
-
-/* 512-byte page with 4-bit ECC, 16-bit */
-static struct nand_ecclayout oob_512_16bit_ecc4 = {
- .eccbytes = 8,
- .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
- .oobfree = { {2, 6}, },
-};
-
-/* 2048-byte page size with 4-bit ECC */
-static struct nand_ecclayout oob_2048_ecc4 = {
- .eccbytes = 32,
- .eccpos = {
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- },
- .oobfree = { {2, 6}, {40, 24} },
-};
-
-/* 4096-byte page size with 4-bit ECC */
-static struct nand_ecclayout oob_4096_ecc4 = {
- .eccbytes = 64,
- .eccpos = {
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71,
- },
- .oobfree = { {2, 6}, {72, 56} },
-};
-
-/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */
-static struct nand_ecclayout oob_4096_ecc8 = {
- .eccbytes = 128,
- .eccpos = {
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119,
- 120, 121, 122, 123, 124, 125, 126, 127,
- 128, 129, 130, 131, 132, 133, 134, 135,
- },
- .oobfree = { {2, 6}, {136, 82} },
-};
-
-/* 8192-byte page size with 4-bit ECC */
-static struct nand_ecclayout oob_8192_ecc4 = {
- .eccbytes = 128,
- .eccpos = {
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119,
- 120, 121, 122, 123, 124, 125, 126, 127,
- 128, 129, 130, 131, 132, 133, 134, 135,
- },
- .oobfree = { {2, 6}, {136, 208} },
-};
-
-/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */
-static struct nand_ecclayout oob_8192_ecc8 = {
- .eccbytes = 256,
- .eccpos = {
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119,
- 120, 121, 122, 123, 124, 125, 126, 127,
- 128, 129, 130, 131, 132, 133, 134, 135,
- 136, 137, 138, 139, 140, 141, 142, 143,
- 144, 145, 146, 147, 148, 149, 150, 151,
- 152, 153, 154, 155, 156, 157, 158, 159,
- 160, 161, 162, 163, 164, 165, 166, 167,
- 168, 169, 170, 171, 172, 173, 174, 175,
- 176, 177, 178, 179, 180, 181, 182, 183,
- 184, 185, 186, 187, 188, 189, 190, 191,
- 192, 193, 194, 195, 196, 197, 198, 199,
- 200, 201, 202, 203, 204, 205, 206, 207,
- 208, 209, 210, 211, 212, 213, 214, 215,
- 216, 217, 218, 219, 220, 221, 222, 223,
- 224, 225, 226, 227, 228, 229, 230, 231,
- 232, 233, 234, 235, 236, 237, 238, 239,
- 240, 241, 242, 243, 244, 245, 246, 247,
- 248, 249, 250, 251, 252, 253, 254, 255,
- 256, 257, 258, 259, 260, 261, 262, 263,
- },
- .oobfree = { {2, 6}, {264, 80} },
-};
-
/*
* Generic flash bbt descriptors
*/
@@ -224,6 +94,55 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.pattern = mirror_pattern,
};

+static int fsl_ifc_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int eccbytes = chip->ecc.bytes * chip->ecc.steps;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return eccbyte + 8;
+}
+
+static int fsl_ifc_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int eccbytes = chip->ecc.bytes * chip->ecc.steps;
+
+ if (section > 1)
+ return -ERANGE;
+
+ if (mtd->writesize == 512 &&
+ !(chip->options & NAND_BUSWIDTH_16)) {
+ if (!section) {
+ oobfree->offset = 0;
+ oobfree->length = 5;
+ } else {
+ oobfree->offset = 6;
+ oobfree->length = 2;
+ }
+
+ return 0;
+ }
+
+ if (!section) {
+ oobfree->offset = 2;
+ oobfree->length = 6;
+ } else {
+ oobfree->offset = eccbytes + 8;
+ oobfree->length = mtd->oobsize - oobfree->offset;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops fsl_ifc_ooblayout_ops = {
+ .eccpos = fsl_ifc_eccpos,
+ .oobfree = fsl_ifc_oobfree,
+};
+
/*
* Set up the IFC hardware block and page address fields, and the ifc nand
* structure addr field to point to the correct IFC buffer in memory
@@ -877,7 +796,6 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
struct nand_chip *chip = &priv->chip;
- struct nand_ecclayout *layout;
u32 csor;

/* Fill in fsl_ifc_mtd structure */
@@ -922,18 +840,9 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)

csor = ifc_in32(&ifc->csor_cs[priv->bank].csor);

- /* Hardware generates ECC per 512 Bytes */
- chip->ecc.size = 512;
- chip->ecc.bytes = 8;
- chip->ecc.strength = 4;
-
switch (csor & CSOR_NAND_PGS_MASK) {
case CSOR_NAND_PGS_512:
- if (chip->options & NAND_BUSWIDTH_16) {
- layout = &oob_512_16bit_ecc4;
- } else {
- layout = &oob_512_8bit_ecc4;
-
+ if (!(chip->options & NAND_BUSWIDTH_16)) {
/* Avoid conflict with bad block marker */
bbt_main_descr.offs = 0;
bbt_mirror_descr.offs = 0;
@@ -943,35 +852,16 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
break;

case CSOR_NAND_PGS_2K:
- layout = &oob_2048_ecc4;
priv->bufnum_mask = 3;
break;

case CSOR_NAND_PGS_4K:
- if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
- CSOR_NAND_ECC_MODE_4) {
- layout = &oob_4096_ecc4;
- } else {
- layout = &oob_4096_ecc8;
- chip->ecc.bytes = 16;
- chip->ecc.strength = 8;
- }
-
priv->bufnum_mask = 1;
break;

case CSOR_NAND_PGS_8K:
- if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
- CSOR_NAND_ECC_MODE_4) {
- layout = &oob_8192_ecc4;
- } else {
- layout = &oob_8192_ecc8;
- chip->ecc.bytes = 16;
- chip->ecc.strength = 8;
- }
-
priv->bufnum_mask = 0;
- break;
+ break;

default:
dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
@@ -981,7 +871,17 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
/* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
if (csor & CSOR_NAND_ECC_DEC_EN) {
chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.layout = layout;
+ mtd_set_ooblayout(&priv->mtd, &fsl_ifc_ooblayout_ops);
+
+ /* Hardware generates ECC per 512 Bytes */
+ chip->ecc.size = 512;
+ if ((csor & CSOR_NAND_ECC_MODE_MASK) == CSOR_NAND_ECC_MODE_4) {
+ chip->ecc.bytes = 8;
+ chip->ecc.strength = 4;
+ } else {
+ chip->ecc.bytes = 16;
+ chip->ecc.strength = 8;
+ }
} else {
chip->ecc.mode = NAND_ECC_SOFT;
}
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 59fc6d0..14fd7f6 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -39,212 +39,6 @@
#include <linux/amba/bus.h>
#include <mtd/mtd-abi.h>

-static struct nand_ecclayout fsmc_ecc1_128_layout = {
- .eccbytes = 24,
- .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52,
- 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116},
- .oobfree = {
- {.offset = 8, .length = 8},
- {.offset = 24, .length = 8},
- {.offset = 40, .length = 8},
- {.offset = 56, .length = 8},
- {.offset = 72, .length = 8},
- {.offset = 88, .length = 8},
- {.offset = 104, .length = 8},
- {.offset = 120, .length = 8}
- }
-};
-
-static struct nand_ecclayout fsmc_ecc1_64_layout = {
- .eccbytes = 12,
- .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52},
- .oobfree = {
- {.offset = 8, .length = 8},
- {.offset = 24, .length = 8},
- {.offset = 40, .length = 8},
- {.offset = 56, .length = 8},
- }
-};
-
-static struct nand_ecclayout fsmc_ecc1_16_layout = {
- .eccbytes = 3,
- .eccpos = {2, 3, 4},
- .oobfree = {
- {.offset = 8, .length = 8},
- }
-};
-
-/*
- * ECC4 layout for NAND of pagesize 8192 bytes & OOBsize 256 bytes. 13*16 bytes
- * of OB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block and 46
- * bytes are free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_256_layout = {
- .eccbytes = 208,
- .eccpos = { 2, 3, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, 13, 14,
- 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30,
- 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46,
- 50, 51, 52, 53, 54, 55, 56,
- 57, 58, 59, 60, 61, 62,
- 66, 67, 68, 69, 70, 71, 72,
- 73, 74, 75, 76, 77, 78,
- 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 92, 93, 94,
- 98, 99, 100, 101, 102, 103, 104,
- 105, 106, 107, 108, 109, 110,
- 114, 115, 116, 117, 118, 119, 120,
- 121, 122, 123, 124, 125, 126,
- 130, 131, 132, 133, 134, 135, 136,
- 137, 138, 139, 140, 141, 142,
- 146, 147, 148, 149, 150, 151, 152,
- 153, 154, 155, 156, 157, 158,
- 162, 163, 164, 165, 166, 167, 168,
- 169, 170, 171, 172, 173, 174,
- 178, 179, 180, 181, 182, 183, 184,
- 185, 186, 187, 188, 189, 190,
- 194, 195, 196, 197, 198, 199, 200,
- 201, 202, 203, 204, 205, 206,
- 210, 211, 212, 213, 214, 215, 216,
- 217, 218, 219, 220, 221, 222,
- 226, 227, 228, 229, 230, 231, 232,
- 233, 234, 235, 236, 237, 238,
- 242, 243, 244, 245, 246, 247, 248,
- 249, 250, 251, 252, 253, 254
- },
- .oobfree = {
- {.offset = 15, .length = 3},
- {.offset = 31, .length = 3},
- {.offset = 47, .length = 3},
- {.offset = 63, .length = 3},
- {.offset = 79, .length = 3},
- {.offset = 95, .length = 3},
- {.offset = 111, .length = 3},
- {.offset = 127, .length = 3},
- {.offset = 143, .length = 3},
- {.offset = 159, .length = 3},
- {.offset = 175, .length = 3},
- {.offset = 191, .length = 3},
- {.offset = 207, .length = 3},
- {.offset = 223, .length = 3},
- {.offset = 239, .length = 3},
- {.offset = 255, .length = 1}
- }
-};
-
-/*
- * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 224 bytes. 13*8 bytes
- * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 118
- * bytes are free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_224_layout = {
- .eccbytes = 104,
- .eccpos = { 2, 3, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, 13, 14,
- 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30,
- 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46,
- 50, 51, 52, 53, 54, 55, 56,
- 57, 58, 59, 60, 61, 62,
- 66, 67, 68, 69, 70, 71, 72,
- 73, 74, 75, 76, 77, 78,
- 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 92, 93, 94,
- 98, 99, 100, 101, 102, 103, 104,
- 105, 106, 107, 108, 109, 110,
- 114, 115, 116, 117, 118, 119, 120,
- 121, 122, 123, 124, 125, 126
- },
- .oobfree = {
- {.offset = 15, .length = 3},
- {.offset = 31, .length = 3},
- {.offset = 47, .length = 3},
- {.offset = 63, .length = 3},
- {.offset = 79, .length = 3},
- {.offset = 95, .length = 3},
- {.offset = 111, .length = 3},
- {.offset = 127, .length = 97}
- }
-};
-
-/*
- * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 128 bytes. 13*8 bytes
- * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 22
- * bytes are free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_128_layout = {
- .eccbytes = 104,
- .eccpos = { 2, 3, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, 13, 14,
- 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30,
- 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46,
- 50, 51, 52, 53, 54, 55, 56,
- 57, 58, 59, 60, 61, 62,
- 66, 67, 68, 69, 70, 71, 72,
- 73, 74, 75, 76, 77, 78,
- 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 92, 93, 94,
- 98, 99, 100, 101, 102, 103, 104,
- 105, 106, 107, 108, 109, 110,
- 114, 115, 116, 117, 118, 119, 120,
- 121, 122, 123, 124, 125, 126
- },
- .oobfree = {
- {.offset = 15, .length = 3},
- {.offset = 31, .length = 3},
- {.offset = 47, .length = 3},
- {.offset = 63, .length = 3},
- {.offset = 79, .length = 3},
- {.offset = 95, .length = 3},
- {.offset = 111, .length = 3},
- {.offset = 127, .length = 1}
- }
-};
-
-/*
- * ECC4 layout for NAND of pagesize 2048 bytes & OOBsize 64 bytes. 13*4 bytes of
- * OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block and 10
- * bytes are free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_64_layout = {
- .eccbytes = 52,
- .eccpos = { 2, 3, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, 13, 14,
- 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30,
- 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46,
- 50, 51, 52, 53, 54, 55, 56,
- 57, 58, 59, 60, 61, 62,
- },
- .oobfree = {
- {.offset = 15, .length = 3},
- {.offset = 31, .length = 3},
- {.offset = 47, .length = 3},
- {.offset = 63, .length = 1},
- }
-};
-
-/*
- * ECC4 layout for NAND of pagesize 512 bytes & OOBsize 16 bytes. 13 bytes of
- * OOB size is reserved for ECC, Byte no. 4 & 5 reserved for bad block and One
- * byte is free for use.
- */
-static struct nand_ecclayout fsmc_ecc4_16_layout = {
- .eccbytes = 13,
- .eccpos = { 0, 1, 2, 3, 6, 7, 8,
- 9, 10, 11, 12, 13, 14
- },
- .oobfree = {
- {.offset = 15, .length = 1},
- }
-};
-
/*
* ECC placement definitions in oobfree type format.
* There are 13 bytes of ecc for every 512 byte block and it has to be read
@@ -274,6 +68,80 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {
}
};

+static int fsmc_ecc1_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int eccbytes = chip->ecc.bytes * chip->ecc.steps;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return ((eccbyte / 3) * 16) + (eccbyte % 3) + 2;
+}
+
+static int fsmc_ecc1_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (section >= chip->ecc.steps)
+ return -ERANGE;
+
+ oobfree->offset = (section * 16) + 8;
+
+ if (section < chip->ecc.steps - 1)
+ oobfree->length = 8;
+ else
+ oobfree->length = mtd->oobsize - oobfree->offset;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops fsmc_ecc1_ooblayout_ops = {
+ .eccpos = fsmc_ecc1_eccpos,
+ .oobfree = fsmc_ecc1_oobfree,
+};
+
+static int fsmc_ecc4_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int eccbytes = chip->ecc.bytes * chip->ecc.steps;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ if (mtd->writesize > 512)
+ return ((eccbyte / 13) * 16) + (eccbyte % 13) + 2;
+
+ if (eccbyte < 4)
+ return eccbyte;
+
+ return eccbyte + 2;
+}
+
+static int fsmc_ecc4_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (section >= chip->ecc.steps)
+ return -ERANGE;
+
+ oobfree->offset = (section * 16) + 15;
+
+ if (section < chip->ecc.steps - 1)
+ oobfree->length = 3;
+ else
+ oobfree->length = mtd->oobsize - oobfree->offset;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
+ .eccpos = fsmc_ecc4_eccpos,
+ .oobfree = fsmc_ecc4_oobfree,
+};
+
/**
* struct fsmc_nand_data - structure for FSMC NAND device state
*
@@ -1089,23 +957,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (AMBA_REV_BITS(host->pid) >= 8) {
switch (host->mtd.oobsize) {
case 16:
- nand->ecc.layout = &fsmc_ecc4_16_layout;
host->ecc_place = &fsmc_ecc4_sp_place;
break;
case 64:
- nand->ecc.layout = &fsmc_ecc4_64_layout;
host->ecc_place = &fsmc_ecc4_lp_place;
break;
case 128:
- nand->ecc.layout = &fsmc_ecc4_128_layout;
host->ecc_place = &fsmc_ecc4_lp_place;
break;
case 224:
- nand->ecc.layout = &fsmc_ecc4_224_layout;
host->ecc_place = &fsmc_ecc4_lp_place;
break;
case 256:
- nand->ecc.layout = &fsmc_ecc4_256_layout;
host->ecc_place = &fsmc_ecc4_lp_place;
break;
default:
@@ -1114,6 +977,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
ret = -EINVAL;
goto err_probe;
}
+
+ mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
} else {
switch (nand->ecc.mode) {
case NAND_ECC_HW:
@@ -1140,13 +1005,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (nand->ecc.mode != NAND_ECC_SOFT_BCH) {
switch (host->mtd.oobsize) {
case 16:
- nand->ecc.layout = &fsmc_ecc1_16_layout;
- break;
case 64:
- nand->ecc.layout = &fsmc_ecc1_64_layout;
- break;
case 128:
- nand->ecc.layout = &fsmc_ecc1_128_layout;
+ mtd_set_ooblayout(mtd,
+ &fsmc_ecc1_ooblayout_ops);
break;
default:
dev_warn(&pdev->dev,
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index c208f5e..9894843 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -47,10 +47,41 @@ static struct nand_bbt_descr gpmi_bbt_descr = {
* We may change the layout if we can get the ECC info from the datasheet,
* else we will use all the (page + OOB).
*/
-static struct nand_ecclayout gpmi_hw_ecclayout = {
- .eccbytes = 0,
- .eccpos = { 0, },
- .oobfree = { {.offset = 0, .length = 0} }
+static int gpmi_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = chip->priv;
+ struct bch_geometry *geo = &this->bch_geometry;
+ int eccbytes = geo->page_size - mtd->writesize;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return eccbyte;
+}
+
+static int gpmi_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = chip->priv;
+ struct bch_geometry *geo = &this->bch_geometry;
+
+ if (section)
+ return -ERANGE;
+
+ /* The available oob size we have. */
+ if (geo->page_size < mtd->writesize + mtd->oobsize) {
+ oobfree->offset = geo->page_size - mtd->writesize;
+ oobfree->length = mtd->oobsize - oobfree->offset;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
+ .eccpos = gpmi_eccpos,
+ .oobfree = gpmi_oobfree,
};

static const struct gpmi_devdata gpmi_devdata_imx23 = {
@@ -141,7 +172,6 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
struct bch_geometry *geo = &this->bch_geometry;
struct mtd_info *mtd = &this->mtd;
struct nand_chip *chip = mtd->priv;
- struct nand_oobfree *of = gpmi_hw_ecclayout.oobfree;
unsigned int block_mark_bit_offset;

if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
@@ -229,12 +259,6 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
geo->page_size = mtd->writesize + geo->metadata_size +
(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;

- /* The available oob size we have. */
- if (geo->page_size < mtd->writesize + mtd->oobsize) {
- of->offset = geo->page_size - mtd->writesize;
- of->length = mtd->oobsize - of->offset;
- }
-
geo->payload_size = mtd->writesize;

geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
@@ -1861,7 +1885,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
ecc->mode = NAND_ECC_HW;
ecc->size = bch_geo->ecc_chunk_size;
ecc->strength = bch_geo->ecc_strength;
- ecc->layout = &gpmi_hw_ecclayout;
+ mtd_set_ooblayout(mtd, &gpmi_ooblayout_ops);

/*
* We only enable the subpage read when:
diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
index 32a5a4c..dd12cd7 100644
--- a/drivers/mtd/nand/hisi504_nand.c
+++ b/drivers/mtd/nand/hisi504_nand.c
@@ -632,8 +632,28 @@ static void hisi_nfc_host_init(struct hinfc_host *host)
hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
}

-static struct nand_ecclayout nand_ecc_2K_16bits = {
- .oobfree = { {2, 6} },
+static int hisi_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ /* FIXME: add real eccpos definition. */
+ return 0;
+}
+
+static int hisi_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ /* FIXME: add full oobfree definition. */
+ if (section)
+ return -ERANGE;
+
+ oobfree->offset = 2;
+ oobfree->length = 6;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops hisi_ooblayout_ops = {
+ .eccpos = hisi_eccpos,
+ .oobfree = hisi_oobfree,
};

static int hisi_nfc_ecc_probe(struct hinfc_host *host)
@@ -669,7 +689,7 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
case 16:
ecc_bits = 6;
if (mtd->writesize == 2048)
- chip->ecc.layout = &nand_ecc_2K_16bits;
+ mtd_set_ooblayout(mtd, &hisi_ooblayout_ops);

/* TODO: add more page size support */
break;
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index c4fe446..ec8bd6d 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -495,7 +495,7 @@ static int jz_nand_probe(struct platform_device *pdev)
}

if (pdata && pdata->ident_callback) {
- pdata->ident_callback(pdev, chip, &pdata->partitions,
+ pdata->ident_callback(pdev, mtd, &pdata->partitions,
&pdata->num_partitions);
}

diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index 0ee81a0..80f66ac 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -139,22 +139,36 @@ struct lpc32xx_nand_cfg_mlc {
unsigned num_parts;
};

-static struct nand_ecclayout lpc32xx_nand_oob = {
- .eccbytes = 40,
- .eccpos = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
- .oobfree = {
- { .offset = 0,
- .length = 6, },
- { .offset = 16,
- .length = 6, },
- { .offset = 32,
- .length = 6, },
- { .offset = 48,
- .length = 6, },
- },
+static int lpc32xx_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ int eccbytes = nand_chip->ecc.steps * nand_chip->ecc.bytes;
+ int off = 16 - nand_chip->ecc.bytes;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return ((eccbyte / nand_chip->ecc.bytes) * 16) + off +
+ (eccbyte % nand_chip->ecc.bytes);
+}
+
+static int lpc32xx_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+
+ if (section >= nand_chip->ecc.steps)
+ return -ERANGE;
+
+ oobfree->offset = 16 * section;
+ oobfree->length = 16 - nand_chip->ecc.bytes;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
+ .eccpos = lpc32xx_eccpos,
+ .oobfree = lpc32xx_oobfree,
};

static struct nand_bbt_descr lpc32xx_nand_bbt = {
@@ -714,6 +728,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
nand_chip->ecc.write_oob = lpc32xx_write_oob;
nand_chip->ecc.read_oob = lpc32xx_read_oob;
nand_chip->ecc.strength = 4;
+ nand_chip->ecc.bytes = 10;
nand_chip->waitfunc = lpc32xx_waitfunc;

nand_chip->options = NAND_NO_SUBPAGE_WRITE;
@@ -752,7 +767,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)

nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512;
- nand_chip->ecc.layout = &lpc32xx_nand_oob;
+ mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
host->mlcsubpages = mtd->writesize / 512;

/* initially clear interrupt status */
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index 47dcfddd..3301c77 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -146,13 +146,34 @@
* NAND ECC Layout for small page NAND devices
* Note: For large and huge page devices, the default layouts are used
*/
-static struct nand_ecclayout lpc32xx_nand_oob_16 = {
- .eccbytes = 6,
- .eccpos = {10, 11, 12, 13, 14, 15},
- .oobfree = {
- { .offset = 0, .length = 4 },
- { .offset = 6, .length = 4 },
- },
+static int lpc32xx_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte > 5)
+ return -ERANGE;
+
+ return eccbyte + 10;
+}
+
+static int lpc32xx_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section > 1)
+ return -ERANGE;
+
+ if (!section) {
+ oobfree->offset = 0;
+ oobfree->length = 4;
+ } else {
+ oobfree->offset = 6;
+ oobfree->length = 4;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
+ .eccpos = lpc32xx_eccpos,
+ .oobfree = lpc32xx_oobfree,
};

static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
@@ -877,7 +898,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
* custom BBT marker layout.
*/
if (mtd->writesize <= 512)
- chip->ecc.layout = &lpc32xx_nand_oob_16;
+ mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);

/* These sizes remain the same regardless of page size */
chip->ecc.size = 256;
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index f507d36..7ea9c50 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -149,7 +149,7 @@ struct mxc_nand_devtype_data {
int (*check_int)(struct mxc_nand_host *);
void (*irq_control)(struct mxc_nand_host *, int);
u32 (*get_ecc_status)(struct mxc_nand_host *);
- struct nand_ecclayout *ecclayout_512, *ecclayout_2k, *ecclayout_4k;
+ const struct mtd_ooblayout_ops *ooblayout;
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*correct_data)(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc);
@@ -201,73 +201,6 @@ struct mxc_nand_host {
struct mxc_nand_platform_data pdata;
};

-/* OOB placement block for use with hardware ecc generation */
-static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
- .eccbytes = 5,
- .eccpos = {6, 7, 8, 9, 10},
- .oobfree = {{0, 5}, {12, 4}, }
-};
-
-static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
- .eccbytes = 20,
- .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
- 38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
- .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
-};
-
-/* OOB description for 512 byte pages with 16 byte OOB */
-static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
- .eccbytes = 1 * 9,
- .eccpos = {
- 7, 8, 9, 10, 11, 12, 13, 14, 15
- },
- .oobfree = {
- {.offset = 0, .length = 5}
- }
-};
-
-/* OOB description for 2048 byte pages with 64 byte OOB */
-static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
- .eccbytes = 4 * 9,
- .eccpos = {
- 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 55, 56, 57, 58, 59, 60, 61, 62, 63
- },
- .oobfree = {
- {.offset = 2, .length = 4},
- {.offset = 16, .length = 7},
- {.offset = 32, .length = 7},
- {.offset = 48, .length = 7}
- }
-};
-
-/* OOB description for 4096 byte pages with 128 byte OOB */
-static struct nand_ecclayout nandv2_hw_eccoob_4k = {
- .eccbytes = 8 * 9,
- .eccpos = {
- 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 87, 88, 89, 90, 91, 92, 93, 94, 95,
- 103, 104, 105, 106, 107, 108, 109, 110, 111,
- 119, 120, 121, 122, 123, 124, 125, 126, 127,
- },
- .oobfree = {
- {.offset = 2, .length = 4},
- {.offset = 16, .length = 7},
- {.offset = 32, .length = 7},
- {.offset = 48, .length = 7},
- {.offset = 64, .length = 7},
- {.offset = 80, .length = 7},
- {.offset = 96, .length = 7},
- {.offset = 112, .length = 7},
- }
-};
-
static const char * const part_probes[] = {
"cmdlinepart", "RedBoot", "ofpart", NULL };

@@ -943,6 +876,93 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
}
}

+static int mxc_v1_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ int eccbytes = nand_chip->ecc.steps * nand_chip->ecc.bytes;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return ((eccbyte / nand_chip->ecc.bytes) * 16) + 6 +
+ (eccbyte % nand_chip->ecc.bytes);
+}
+
+static int mxc_v1_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+
+ if (section > nand_chip->ecc.steps)
+ return -ERANGE;
+
+ if (!section) {
+ if (mtd->writesize <= 512) {
+ oobfree->offset = 0;
+ oobfree->length = 5;
+ } else {
+ oobfree->offset = 2;
+ oobfree->length = 4;
+ }
+ } else {
+ oobfree->offset = ((section - 1) * 16) +
+ nand_chip->ecc.bytes + 6;
+ if (section < nand_chip->ecc.steps)
+ oobfree->length = (section * 16) + 6 - oobfree->offset;
+ else
+ oobfree->length = mtd->oobsize - oobfree->offset;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
+ .eccpos = mxc_v1_eccpos,
+ .oobfree = mxc_v1_oobfree,
+};
+
+static int mxc_v2_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ int eccbytes = nand_chip->ecc.steps * nand_chip->ecc.bytes;
+ int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return ((eccbyte / nand_chip->ecc.bytes) * stepsize) + 7;
+}
+
+static int mxc_v2_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
+
+ if (section > nand_chip->ecc.steps)
+ return -ERANGE;
+
+ if (!section) {
+ if (mtd->writesize <= 512) {
+ oobfree->offset = 0;
+ oobfree->length = 5;
+ } else {
+ oobfree->offset = 2;
+ oobfree->length = 4;
+ }
+ } else {
+ oobfree->offset = section * stepsize;
+ oobfree->length = 7;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = {
+ .eccpos = mxc_v2_eccpos,
+ .oobfree = mxc_v2_oobfree,
+};
+
/*
* v2 and v3 type controllers can do 4bit or 8bit ecc depending
* on how much oob the nand chip has. For 8bit ecc we need at least
@@ -960,23 +980,6 @@ static int get_eccsize(struct mtd_info *mtd)
return 8;
}

-static void ecc_8bit_layout_4k(struct nand_ecclayout *layout)
-{
- int i, j;
-
- layout->eccbytes = 8*18;
- for (i = 0; i < 8; i++)
- for (j = 0; j < 18; j++)
- layout->eccpos[i*18 + j] = i*26 + j + 7;
-
- layout->oobfree[0].offset = 2;
- layout->oobfree[0].length = 4;
- for (i = 1; i < 8; i++) {
- layout->oobfree[i].offset = i*26;
- layout->oobfree[i].length = 7;
- }
-}
-
static void preset_v1(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd->priv;
@@ -1270,9 +1273,7 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
.check_int = check_int_v1_v2,
.irq_control = irq_control_v1_v2,
.get_ecc_status = get_ecc_status_v1,
- .ecclayout_512 = &nandv1_hw_eccoob_smallpage,
- .ecclayout_2k = &nandv1_hw_eccoob_largepage,
- .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
+ .ooblayout = &mxc_v1_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v1,
.irqpending_quirk = 1,
@@ -1295,9 +1296,7 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
.check_int = check_int_v1_v2,
.irq_control = irq_control_v1_v2,
.get_ecc_status = get_ecc_status_v1,
- .ecclayout_512 = &nandv1_hw_eccoob_smallpage,
- .ecclayout_2k = &nandv1_hw_eccoob_largepage,
- .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
+ .ooblayout = &mxc_v1_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v1,
.irqpending_quirk = 0,
@@ -1321,9 +1320,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.check_int = check_int_v1_v2,
.irq_control = irq_control_v1_v2,
.get_ecc_status = get_ecc_status_v2,
- .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
- .ecclayout_2k = &nandv2_hw_eccoob_largepage,
- .ecclayout_4k = &nandv2_hw_eccoob_4k,
+ .ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v2,
.correct_data = mxc_nand_correct_data_v2_v3,
.irqpending_quirk = 0,
@@ -1347,9 +1344,7 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
.check_int = check_int_v3,
.irq_control = irq_control_v3,
.get_ecc_status = get_ecc_status_v3,
- .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
- .ecclayout_2k = &nandv2_hw_eccoob_largepage,
- .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
+ .ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v2_v3,
.irqpending_quirk = 0,
@@ -1374,9 +1369,7 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
.check_int = check_int_v3,
.irq_control = irq_control_v3,
.get_ecc_status = get_ecc_status_v3,
- .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
- .ecclayout_2k = &nandv2_hw_eccoob_largepage,
- .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
+ .ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v2_v3,
.irqpending_quirk = 0,
@@ -1578,7 +1571,7 @@ static int mxcnd_probe(struct platform_device *pdev)

this->select_chip = host->devtype_data->select_chip;
this->ecc.size = 512;
- this->ecc.layout = host->devtype_data->ecclayout_512;
+ mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);

if (host->pdata.hw_ecc) {
this->ecc.calculate = mxc_nand_calculate_ecc;
@@ -1651,12 +1644,11 @@ static int mxcnd_probe(struct platform_device *pdev)
/* Call preset again, with correct writesize this time */
host->devtype_data->preset(mtd);

- if (mtd->writesize == 2048)
- this->ecc.layout = host->devtype_data->ecclayout_2k;
- else if (mtd->writesize == 4096) {
- this->ecc.layout = host->devtype_data->ecclayout_4k;
- if (get_eccsize(mtd) == 8)
- ecc_8bit_layout_4k(this->ecc.layout);
+ if (!this->ecc.bytes) {
+ if (host->eccsize == 8)
+ this->ecc.bytes = 18;
+ else if (host->eccsize == 4)
+ this->ecc.bytes = 9;
}

/*
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 6a598b1..3570e31 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -170,8 +170,6 @@ struct omap_nand_info {
u_char *buf;
int buf_len;
struct gpmc_nand_regs reg;
- /* generated at runtime depending on ECC algorithm and layout selected */
- struct nand_ecclayout oobinfo;
/* fields specific for BCHx_HW ECC scheme */
struct device *elm_dev;
struct device_node *of_node;
@@ -1649,19 +1647,98 @@ static bool omap2_nand_ecc_check(struct omap_nand_info *info,
return true;
}

+static int omap_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int off = chip->options & NAND_BUSWIDTH_16 ?
+ BADBLOCK_MARKER_LENGTH : 1;
+
+ if (eccbyte >= chip->ecc.bytes * chip->ecc.steps)
+ return -ERANGE;
+
+ return eccbyte + off;
+}
+
+static int omap_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int off = chip->options & NAND_BUSWIDTH_16 ?
+ BADBLOCK_MARKER_LENGTH : 1;
+ if (section)
+ return -ERANGE;
+
+ off += chip->ecc.bytes * chip->ecc.steps;
+ if (off >= mtd->oobsize)
+ return -ERANGE;
+
+ oobfree->offset = off;
+ oobfree->length = mtd->oobsize - off;
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops omap_ooblayout_ops = {
+ .eccpos = omap_eccpos,
+ .oobfree = omap_oobfree,
+};
+
+static int omap_sw_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int off = chip->options & NAND_BUSWIDTH_16 ?
+ BADBLOCK_MARKER_LENGTH : 1;
+
+ if (eccbyte >= chip->ecc.bytes * chip->ecc.steps)
+ return -ERANGE;
+
+ /*
+ * When SW correction is employed, one OMAP specific marker byte is
+ * reserved after each ECC step.
+ */
+ return (eccbyte % chip->ecc.bytes) + (eccbyte / chip->ecc.bytes) + off;
+}
+
+static int omap_sw_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int off = chip->options & NAND_BUSWIDTH_16 ?
+ BADBLOCK_MARKER_LENGTH : 1;
+ if (section)
+ return -ERANGE;
+
+ /*
+ * When SW correction is employed, one OMAP specific marker byte is
+ * reserved after each ECC step.
+ */
+ off += ((chip->ecc.bytes + 1) * chip->ecc.steps);
+ if (off >= mtd->oobsize)
+ return -ERANGE;
+
+ oobfree->offset = off;
+ oobfree->length = mtd->oobsize - off;
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
+ .eccpos = omap_sw_eccpos,
+ .oobfree = omap_sw_oobfree,
+};
+
static int omap_nand_probe(struct platform_device *pdev)
{
struct omap_nand_info *info;
struct omap_nand_platform_data *pdata;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
- struct nand_ecclayout *ecclayout;
int err;
- int i;
dma_cap_mask_t mask;
unsigned sig;
- unsigned oob_index;
struct resource *res;
+ int min_oobbytes;
+ int oobbytes_per_step;

pdata = dev_get_platdata(&pdev->dev);
if (pdata == NULL) {
@@ -1821,7 +1898,7 @@ static int omap_nand_probe(struct platform_device *pdev)

/*
* Bail out earlier to let NAND_ECC_SOFT code create its own
- * ecclayout instead of using ours.
+ * ooblayout instead of using ours.
*/
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
nand_chip->ecc.mode = NAND_ECC_SOFT;
@@ -1829,8 +1906,6 @@ static int omap_nand_probe(struct platform_device *pdev)
}

/* populate MTD interface based on ECC scheme */
- ecclayout = &info->oobinfo;
- nand_chip->ecc.layout = ecclayout;
switch (info->ecc_opt) {
case OMAP_ECC_HAM1_CODE_HW:
pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
@@ -1841,19 +1916,8 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.calculate = omap_calculate_ecc;
nand_chip->ecc.hwctl = omap_enable_hwecc;
nand_chip->ecc.correct = omap_correct_data;
- /* define ECC layout */
- ecclayout->eccbytes = nand_chip->ecc.bytes *
- (mtd->writesize /
- nand_chip->ecc.size);
- if (nand_chip->options & NAND_BUSWIDTH_16)
- oob_index = BADBLOCK_MARKER_LENGTH;
- else
- oob_index = 1;
- for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
- ecclayout->eccpos[i] = oob_index;
- /* no reserved-marker in ecclayout for this ecc-scheme */
- ecclayout->oobfree->offset =
- ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = nand_chip->ecc.bytes;
break;

case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
@@ -1865,19 +1929,9 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
nand_chip->ecc.correct = nand_bch_correct_data;
nand_chip->ecc.calculate = omap_calculate_ecc_bch;
- /* define ECC layout */
- ecclayout->eccbytes = nand_chip->ecc.bytes *
- (mtd->writesize /
- nand_chip->ecc.size);
- oob_index = BADBLOCK_MARKER_LENGTH;
- for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
- 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;
+ mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+ /* Reserve one byte for the OMAP marker */
+ oobbytes_per_step = nand_chip->ecc.bytes + 1;
/* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd);
if (!nand_chip->ecc.priv) {
@@ -1899,16 +1953,8 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.calculate = omap_calculate_ecc_bch;
nand_chip->ecc.read_page = omap_read_page_bch;
nand_chip->ecc.write_page = omap_write_page_bch;
- /* define ECC layout */
- ecclayout->eccbytes = nand_chip->ecc.bytes *
- (mtd->writesize /
- nand_chip->ecc.size);
- oob_index = BADBLOCK_MARKER_LENGTH;
- for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
- ecclayout->eccpos[i] = oob_index;
- /* reserved marker already included in ecclayout->eccbytes */
- ecclayout->oobfree->offset =
- ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = nand_chip->ecc.bytes;

err = elm_config(info->elm_dev, BCH4_ECC,
info->mtd.writesize / nand_chip->ecc.size,
@@ -1926,19 +1972,9 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
nand_chip->ecc.correct = nand_bch_correct_data;
nand_chip->ecc.calculate = omap_calculate_ecc_bch;
- /* define ECC layout */
- ecclayout->eccbytes = nand_chip->ecc.bytes *
- (mtd->writesize /
- nand_chip->ecc.size);
- oob_index = BADBLOCK_MARKER_LENGTH;
- for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
- 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;
+ mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+ /* Reserve one byte for the OMAP marker */
+ oobbytes_per_step = nand_chip->ecc.bytes + 1;
/* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd);
if (!nand_chip->ecc.priv) {
@@ -1960,6 +1996,8 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.calculate = omap_calculate_ecc_bch;
nand_chip->ecc.read_page = omap_read_page_bch;
nand_chip->ecc.write_page = omap_write_page_bch;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = nand_chip->ecc.bytes;

err = elm_config(info->elm_dev, BCH8_ECC,
info->mtd.writesize / nand_chip->ecc.size,
@@ -1967,16 +2005,6 @@ static int omap_nand_probe(struct platform_device *pdev)
if (err < 0)
goto return_error;

- /* define ECC layout */
- ecclayout->eccbytes = nand_chip->ecc.bytes *
- (mtd->writesize /
- nand_chip->ecc.size);
- oob_index = BADBLOCK_MARKER_LENGTH;
- for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
- ecclayout->eccpos[i] = oob_index;
- /* reserved marker already included in ecclayout->eccbytes */
- ecclayout->oobfree->offset =
- ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
break;

case OMAP_ECC_BCH16_CODE_HW:
@@ -1990,6 +2018,8 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.calculate = omap_calculate_ecc_bch;
nand_chip->ecc.read_page = omap_read_page_bch;
nand_chip->ecc.write_page = omap_write_page_bch;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = nand_chip->ecc.bytes;

err = elm_config(info->elm_dev, BCH16_ECC,
info->mtd.writesize / nand_chip->ecc.size,
@@ -1997,16 +2027,6 @@ static int omap_nand_probe(struct platform_device *pdev)
if (err < 0)
goto return_error;

- /* define ECC layout */
- ecclayout->eccbytes = nand_chip->ecc.bytes *
- (mtd->writesize /
- nand_chip->ecc.size);
- oob_index = BADBLOCK_MARKER_LENGTH;
- for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
- ecclayout->eccpos[i] = oob_index;
- /* reserved marker already included in ecclayout->eccbytes */
- ecclayout->oobfree->offset =
- ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
break;
default:
dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
@@ -2014,13 +2034,15 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error;
}

- /* all OOB bytes from oobfree->offset till end off OOB are free */
- ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
/* check if NAND device's OOB is enough to store ECC signatures */
- if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
+ min_oobbytes = (oobbytes_per_step *
+ (mtd->writesize / nand_chip->ecc.size)) +
+ (nand_chip->options & NAND_BUSWIDTH_16 ?
+ BADBLOCK_MARKER_LENGTH : 1);
+ if (mtd->oobsize < min_oobbytes) {
dev_err(&info->pdev->dev,
"not enough OOB bytes required = %d, available=%d\n",
- ecclayout->eccbytes, mtd->oobsize);
+ min_oobbytes, mtd->oobsize);
err = -EINVAL;
goto return_error;
}
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index bdbc2c2..d0f163f 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -285,6 +285,59 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
{ 0xba20, 16, 16, &timing[3] },
};

+static int pxa3xx_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = chip->priv;
+ struct pxa3xx_nand_info *info = host->info_data;
+ int chunk = eccbyte / info->ecc_size;
+ int nchunks = mtd->writesize / info->chunk_size;
+
+ if (chunk >= nchunks)
+ return -ERANGE;
+
+ return (eccbyte % info->ecc_size) + info->spare_size +
+ ((info->ecc_size + info->spare_size) * chunk);
+}
+
+static int pxa3xx_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct pxa3xx_nand_host *host = chip->priv;
+ struct pxa3xx_nand_info *info = host->info_data;
+ int nchunks = mtd->writesize / info->chunk_size;
+
+ if (section >= nchunks)
+ return -ERANGE;
+
+ if (!info->spare_size)
+ return 0;
+
+ oobfree->offset = section * (info->ecc_size + info->spare_size);
+ oobfree->length = info->spare_size;
+ if (!section) {
+ /*
+ * Bootrom looks in bytes 0 & 5 for bad blocks for the
+ * 4KB page / 4bit BCH combination.
+ */
+ if (mtd->writesize == 4096 && info->chunk_size == 2048) {
+ oobfree->offset += 6;
+ oobfree->length -= 6;
+ } else {
+ oobfree->offset += 2;
+ oobfree->length -= 2;
+ }
+ }
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops pxa3xx_ooblayout_ops = {
+ .eccpos = pxa3xx_eccpos,
+ .oobfree = pxa3xx_oobfree,
+};
+
static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };

@@ -308,41 +361,6 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.pattern = bbt_mirror_pattern
};

-static struct nand_ecclayout ecc_layout_2KB_bch4bit = {
- .eccbytes = 32,
- .eccpos = {
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63},
- .oobfree = { {2, 30} }
-};
-
-static struct nand_ecclayout ecc_layout_4KB_bch4bit = {
- .eccbytes = 64,
- .eccpos = {
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 96, 97, 98, 99, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119,
- 120, 121, 122, 123, 124, 125, 126, 127},
- /* Bootrom looks in bytes 0 & 5 for bad blocks */
- .oobfree = { {6, 26}, { 64, 32} }
-};
-
-static struct nand_ecclayout ecc_layout_4KB_bch8bit = {
- .eccbytes = 128,
- .eccpos = {
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63},
- .oobfree = { }
-};
-
#define NDTR0_tCH(c) (min((c), 7) << 19)
#define NDTR0_tCS(c) (min((c), 7) << 16)
#define NDTR0_tWH(c) (min((c), 7) << 11)
@@ -1502,9 +1520,12 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
}

static int pxa_ecc_init(struct pxa3xx_nand_info *info,
- struct nand_ecc_ctrl *ecc,
+ struct mtd_info *mtd,
int strength, int ecc_stepsize, int page_size)
{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+
if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
info->chunk_size = 2048;
info->spare_size = 40;
@@ -1532,7 +1553,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
info->ecc_size = 32;
ecc->mode = NAND_ECC_HW;
ecc->size = info->chunk_size;
- ecc->layout = &ecc_layout_2KB_bch4bit;
+ mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
ecc->strength = 16;

} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
@@ -1542,7 +1563,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
info->ecc_size = 32;
ecc->mode = NAND_ECC_HW;
ecc->size = info->chunk_size;
- ecc->layout = &ecc_layout_4KB_bch4bit;
+ mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
ecc->strength = 16;

/*
@@ -1556,7 +1577,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
info->ecc_size = 32;
ecc->mode = NAND_ECC_HW;
ecc->size = info->chunk_size;
- ecc->layout = &ecc_layout_4KB_bch8bit;
+ mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
ecc->strength = 16;
} else {
dev_err(&info->pdev->dev,
@@ -1647,7 +1668,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
ecc_step = 512;
}

- ret = pxa_ecc_init(info, &chip->ecc, ecc_strength,
+ ret = pxa_ecc_init(info, mtd, ecc_strength,
ecc_step, mtd->writesize);
if (ret)
return ret;
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index b569200..83c3920 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -84,11 +84,29 @@

/* new oob placement block for use with hardware ecc generation
*/
+static int s3c2410_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte > 2)
+ return -ERANGE;
+
+ return eccbyte;
+}
+
+static int s3c2410_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section)
+ return -ERANGE;
+
+ oobfree->offset = 8;
+ oobfree->length = 8;
+
+ return 0;
+}

-static struct nand_ecclayout nand_hw_eccoob = {
- .eccbytes = 3,
- .eccpos = {0, 1, 2},
- .oobfree = {{8, 8}}
+const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {
+ .eccpos = s3c2410_eccpos,
+ .oobfree = s3c2410_oobfree,
};

/* controller and mtd information */
@@ -918,7 +936,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
} else {
chip->ecc.size = 512;
chip->ecc.bytes = 3;
- chip->ecc.layout = &nand_hw_eccoob;
+ mtd_set_ooblayout(&nmtd->mtd, &s3c2410_ooblayout_ops);
}
}

diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index 57dc525..0430375 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -43,26 +43,66 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/sh_flctl.h>

-static struct nand_ecclayout flctl_4secc_oob_16 = {
- .eccbytes = 10,
- .eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
- .oobfree = {
- {.offset = 12,
- . length = 4} },
+static int flctl_4secc_oob_smallpage_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (eccbyte >= chip->ecc.bytes)
+ return -ERANGE;
+
+ return eccbyte;
+}
+
+static int flctl_4secc_oob_smallpage_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section)
+ return -ERANGE;
+
+ oobfree->offset = 12;
+ oobfree->length = 4;
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops flctl_4secc_oob_smallpage_ops = {
+ .eccpos = flctl_4secc_oob_smallpage_eccpos,
+ .oobfree = flctl_4secc_oob_smallpage_oobfree,
};

-static struct nand_ecclayout flctl_4secc_oob_64 = {
- .eccbytes = 4 * 10,
- .eccpos = {
- 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
- .oobfree = {
- {.offset = 2, .length = 4},
- {.offset = 16, .length = 6},
- {.offset = 32, .length = 6},
- {.offset = 48, .length = 6} },
+static int flctl_4secc_oob_largepage_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (eccbyte >= chip->ecc.bytes * chip->ecc.steps)
+ return -ERANGE;
+
+ return ((eccbyte / chip->ecc.bytes) * 16) + 6 +
+ (eccbyte % chip->ecc.bytes);
+}
+
+static int flctl_4secc_oob_largepage_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (section >= chip->ecc.steps)
+ return -ERANGE;
+
+ oobfree->offset = section * 16;
+ oobfree->length = 6;
+
+ if (!section) {
+ oobfree->offset += 2;
+ oobfree->length -= 2;
+ }
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops flctl_4secc_oob_largepage_ops = {
+ .eccpos = flctl_4secc_oob_largepage_eccpos,
+ .oobfree = flctl_4secc_oob_largepage_oobfree,
};

static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
@@ -987,10 +1027,10 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)

if (flctl->hwecc) {
if (mtd->writesize == 512) {
- chip->ecc.layout = &flctl_4secc_oob_16;
+ mtd_set_ooblayout(mtd, &flctl_4secc_oob_smallpage_ops);
chip->badblock_pattern = &flctl_4secc_smallpage;
} else {
- chip->ecc.layout = &flctl_4secc_oob_64;
+ mtd_set_ooblayout(mtd, &flctl_4secc_oob_largepage_ops);
chip->badblock_pattern = &flctl_4secc_largepage;
}

diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 082b600..e49eb95 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -145,6 +145,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
/* Link the private data with the MTD structure */
sharpsl->mtd.priv = this;
sharpsl->mtd.dev.parent = &pdev->dev;
+ mtd_set_ooblayout(&sharpsl->mtd, data->ecc_layout);

platform_set_drvdata(pdev, sharpsl);

@@ -167,7 +168,6 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
this->ecc.bytes = 3;
this->ecc.strength = 1;
this->badblock_pattern = data->badblock_pattern;
- this->ecc.layout = data->ecc_layout;
this->ecc.hwctl = sharpsl_nand_enable_hwecc;
this->ecc.calculate = sharpsl_nand_calculate_ecc;
this->ecc.correct = nand_correct_data;
diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c
index e06b5e5..398d534 100644
--- a/drivers/mtd/nand/sm_common.c
+++ b/drivers/mtd/nand/sm_common.c
@@ -12,14 +12,46 @@
#include <linux/sizes.h>
#include "sm_common.h"

-static struct nand_ecclayout nand_oob_sm = {
- .eccbytes = 6,
- .eccpos = {8, 9, 10, 13, 14, 15},
- .oobfree = {
- {.offset = 0 , .length = 4}, /* reserved */
- {.offset = 6 , .length = 2}, /* LBA1 */
- {.offset = 11, .length = 2} /* LBA2 */
+static int oob_sm_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte > 5)
+ return -ERANGE;
+
+ if (eccbyte < 3)
+ return eccbyte + 8;
+
+ return eccbyte + 13;
+}
+
+static int oob_sm_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ switch (section) {
+ case 0:
+ /* reserved */
+ oobfree->offset = 0;
+ oobfree->length = 4;
+ break;
+ case 1:
+ /* LBA1 */
+ oobfree->offset = 6;
+ oobfree->length = 2;
+ break;
+ case 2:
+ /* LBA2 */
+ oobfree->offset = 11;
+ oobfree->length = 2;
+ break;
+ default:
+ return -ERANGE;
}
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops oob_sm_ops = {
+ .eccpos = oob_sm_eccpos,
+ .oobfree = oob_sm_oobfree,
};

/* NOTE: This layout is is not compatabable with SmartMedia, */
@@ -28,15 +60,39 @@ static struct nand_ecclayout nand_oob_sm = {
/* If you use smftl, it will bypass this and work correctly */
/* If you not, then you break SmartMedia compliance anyway */

-static struct nand_ecclayout nand_oob_sm_small = {
- .eccbytes = 3,
- .eccpos = {0, 1, 2},
- .oobfree = {
- {.offset = 3 , .length = 2}, /* reserved */
- {.offset = 6 , .length = 2}, /* LBA1 */
+static int oob_sm_small_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte > 2)
+ return -ERANGE;
+
+ return eccbyte;
+}
+
+static int oob_sm_small_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ switch (section) {
+ case 0:
+ /* reserved */
+ oobfree->offset = 3;
+ oobfree->length = 2;
+ break;
+ case 1:
+ /* LBA1 */
+ oobfree->offset = 6;
+ oobfree->length = 2;
+ break;
+ default:
+ return -ERANGE;
}
-};

+ return 0;
+}
+
+const struct mtd_ooblayout_ops oob_sm_small_ops = {
+ .eccpos = oob_sm_small_eccpos,
+ .oobfree = oob_sm_small_oobfree,
+};

static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
@@ -121,9 +177,9 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)

/* ECC layout */
if (mtd->writesize == SM_SECTOR_SIZE)
- chip->ecc.layout = &nand_oob_sm;
+ mtd_set_ooblayout(mtd, &oob_sm_ops);
else if (mtd->writesize == SM_SMALL_PAGE)
- chip->ecc.layout = &nand_oob_sm_small;
+ mtd_set_ooblayout(mtd, &oob_sm_small_ops);
else
return -ENODEV;

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 1bbcc0c..0443410 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -211,12 +211,9 @@ struct sunxi_nand_chip_sel {
* sunxi HW ECC infos: stores information related to HW ECC support
*
* @mode: the sunxi ECC mode field deduced from ECC requirements
- * @layout: the OOB layout depending on the ECC requirements and the
- * selected ECC mode
*/
struct sunxi_nand_hw_ecc {
int mode;
- struct nand_ecclayout layout;
};

/*
@@ -1026,6 +1023,55 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
return sunxi_nand_chip_set_timings(chip, timings);
}

+static int sunxi_nand_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct nand_ecc_ctrl *ecc = &nand->ecc;
+ int eccbytes = ecc->bytes * ecc->steps;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return ((eccbyte / ecc->bytes) * (ecc->bytes + 4)) +
+ (eccbyte % ecc->bytes);
+}
+
+static int sunxi_nand_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct nand_ecc_ctrl *ecc = &nand->ecc;
+
+ if (section > ecc->steps)
+ return -ERANGE;
+
+ /*
+ * The first 2 bytes are used for BB markers, hence we
+ * only have 2 bytes available in the first user data
+ * section.
+ */
+ if (!section && ecc->mode == NAND_ECC_HW) {
+ oobfree->offset = 2;
+ oobfree->length = 2;
+
+ return 0;
+ }
+
+ oobfree->offset = section * (ecc->bytes + 4);
+
+ if (section < ecc->steps)
+ oobfree->length = 4;
+ else
+ oobfree->offset = mtd->oobsize - oobfree->offset;
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
+ .eccpos = sunxi_nand_eccpos,
+ .oobfree = sunxi_nand_oobfree,
+};
+
static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc,
struct device_node *np)
@@ -1035,7 +1081,6 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
struct sunxi_nand_hw_ecc *data;
- struct nand_ecclayout *layout;
int nsectors;
int ret;
int i;
@@ -1064,7 +1109,6 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
/* HW ECC always work with even numbers of ECC bytes */
ecc->bytes = ALIGN(ecc->bytes, 2);

- layout = &data->layout;
nsectors = mtd->writesize / ecc->size;

if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
@@ -1072,9 +1116,7 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
goto err;
}

- layout->eccbytes = (ecc->bytes * nsectors);
-
- ecc->layout = layout;
+ mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
ecc->priv = data;

return 0;
@@ -1094,9 +1136,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc,
struct device_node *np)
{
- struct nand_ecclayout *layout;
- int nsectors;
- int i, j;
int ret;

ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
@@ -1105,40 +1144,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,

ecc->read_page = sunxi_nfc_hw_ecc_read_page;
ecc->write_page = sunxi_nfc_hw_ecc_write_page;
- layout = ecc->layout;
- nsectors = mtd->writesize / ecc->size;
-
- for (i = 0; i < nsectors; i++) {
- if (i) {
- layout->oobfree[i].offset =
- layout->oobfree[i - 1].offset +
- layout->oobfree[i - 1].length +
- ecc->bytes;
- layout->oobfree[i].length = 4;
- } else {
- /*
- * The first 2 bytes are used for BB markers, hence we
- * only have 2 bytes available in the first user data
- * section.
- */
- layout->oobfree[i].length = 2;
- layout->oobfree[i].offset = 2;
- }
-
- for (j = 0; j < ecc->bytes; j++)
- layout->eccpos[(ecc->bytes * i) + j] =
- layout->oobfree[i].offset +
- layout->oobfree[i].length + j;
- }
-
- if (mtd->oobsize > (ecc->bytes + 4) * nsectors) {
- layout->oobfree[nsectors].offset =
- layout->oobfree[nsectors - 1].offset +
- layout->oobfree[nsectors - 1].length +
- ecc->bytes;
- layout->oobfree[nsectors].length = mtd->oobsize -
- ((ecc->bytes + 4) * nsectors);
- }

return 0;
}
@@ -1147,9 +1152,6 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc,
struct device_node *np)
{
- struct nand_ecclayout *layout;
- int nsectors;
- int i;
int ret;

ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
@@ -1160,15 +1162,6 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page;
ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page;

- layout = ecc->layout;
- nsectors = mtd->writesize / ecc->size;
-
- for (i = 0; i < (ecc->bytes * nsectors); i++)
- layout->eccpos[i] = i;
-
- layout->oobfree[0].length = mtd->oobsize - i;
- layout->oobfree[0].offset = i;
-
return 0;
}

@@ -1180,7 +1173,6 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc);
break;
case NAND_ECC_NONE:
- kfree(ecc->layout);
default:
break;
}
@@ -1214,10 +1206,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
return ret;
break;
case NAND_ECC_NONE:
- ecc->layout = kzalloc(sizeof(*ecc->layout), GFP_KERNEL);
- if (!ecc->layout)
- return -ENOMEM;
- ecc->layout->oobfree[0].length = mtd->oobsize;
case NAND_ECC_SOFT:
break;
default:
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 0413e24..9055ee5 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -173,34 +173,6 @@ struct vf610_nfc {

#define mtd_to_nfc(_mtd) container_of(_mtd, struct vf610_nfc, mtd)

-static struct nand_ecclayout vf610_nfc_ecc45 = {
- .eccbytes = 45,
- .eccpos = {19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63},
- .oobfree = {
- {.offset = 2,
- .length = 17} }
-};
-
-static struct nand_ecclayout vf610_nfc_ecc60 = {
- .eccbytes = 60,
- .eccpos = { 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35,
- 36, 37, 38, 39, 40, 41, 42, 43,
- 44, 45, 46, 47, 48, 49, 50, 51,
- 52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, 62, 63 },
- .oobfree = {
- {.offset = 2,
- .length = 2} }
-};
-
static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
{
return readl(nfc->regs + reg);
@@ -780,14 +752,16 @@ static int vf610_nfc_probe(struct platform_device *pdev)
if (mtd->oobsize > 64)
mtd->oobsize = 64;

+ /*
+ * mtd->ecclayout is not specified here because we're using the
+ * default large page ECC layout defined in NAND core.
+ */
if (chip->ecc.strength == 32) {
nfc->ecc_mode = ECC_60_BYTE;
chip->ecc.bytes = 60;
- chip->ecc.layout = &vf610_nfc_ecc60;
} else if (chip->ecc.strength == 24) {
nfc->ecc_mode = ECC_45_BYTE;
chip->ecc.bytes = 45;
- chip->ecc.layout = &vf610_nfc_ecc45;
} else {
dev_err(nfc->dev, "Unsupported ECC strength\n");
err = -ENXIO;
diff --git a/include/linux/mtd/sharpsl.h b/include/linux/mtd/sharpsl.h
index 25f4d2a..a8c23b2 100644
--- a/include/linux/mtd/sharpsl.h
+++ b/include/linux/mtd/sharpsl.h
@@ -14,7 +14,7 @@

struct sharpsl_nand_platform_data {
struct nand_bbt_descr *badblock_pattern;
- struct nand_ecclayout *ecc_layout;
+ struct nand_ooblayout_ops *ecc_layout;
struct mtd_partition *partitions;
unsigned int nr_partitions;
};
--
2.1.4

2015-12-07 22:27:57

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 20/23] mtd: onenand: switch to mtd_ooblayout_ops

Implementing the mtd_ooblayout_ops interface is the new way of exposing
ECC/OOB layout to MTD users. Modify the onenand drivers to switch to this
approach.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/onenand/onenand_base.c | 144 +++++++++++++++++++++----------------
include/linux/mtd/onenand.h | 2 -
2 files changed, 82 insertions(+), 64 deletions(-)

diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index b5937b7..5c7ff9f 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -68,21 +68,29 @@ MODULE_PARM_DESC(otp, "Corresponding behaviour of OneNAND in OTP"
* flexonenand_oob_128 - oob info for Flex-Onenand with 4KB page
* For now, we expose only 64 out of 80 ecc bytes
*/
-static struct nand_ecclayout flexonenand_oob_128 = {
- .eccbytes = 64,
- .eccpos = {
- 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
- 102, 103, 104, 105
- },
- .oobfree = {
- {2, 4}, {18, 4}, {34, 4}, {50, 4},
- {66, 4}, {82, 4}, {98, 4}, {114, 4}
- }
+static int flexonenand_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte > 79)
+ return -ERANGE;
+
+ return ((eccbyte / 10) * 16) + 6 + (eccbyte % 10);
+}
+
+static int flexonenand_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section > 7)
+ return -ERANGE;
+
+ oobfree->offset = (section * 16) + 2;
+ oobfree->length = 4;
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops flexonenand_ooblayout_ops = {
+ .eccpos = flexonenand_eccpos,
+ .oobfree = flexonenand_oobfree,
};

/*
@@ -91,56 +99,69 @@ static struct nand_ecclayout flexonenand_oob_128 = {
* Based on specification:
* 4Gb M-die OneNAND Flash (KFM4G16Q4M, KFN8G16Q4M). Rev. 1.3, Apr. 2010
*
- * For eccpos we expose only 64 bytes out of 72 (see struct nand_ecclayout)
- *
* oobfree uses the spare area fields marked as
* "Managed by internal ECC logic for Logical Sector Number area"
*/
-static struct nand_ecclayout onenand_oob_128 = {
- .eccbytes = 64,
- .eccpos = {
- 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 87, 88, 89, 90, 91, 92, 93, 94, 95,
- 103, 104, 105, 106, 107, 108, 109, 110, 111,
- 119
- },
- .oobfree = {
- {2, 3}, {18, 3}, {34, 3}, {50, 3},
- {66, 3}, {82, 3}, {98, 3}, {114, 3}
- }
+static int onenand_oob_128_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte >= 72)
+ return -ERANGE;
+
+ return ((eccbyte / 9) * 16) + 7 + (eccbyte % 9);
+}
+
+static int onenand_oob_128_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section >= 8)
+ return -ERANGE;
+
+ oobfree->offset = (section * 16) + 2;
+ oobfree->length = 3;
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops onenand_oob_128_ooblayout_ops = {
+ .eccpos = onenand_oob_128_eccpos,
+ .oobfree = onenand_oob_128_oobfree,
};

/**
- * onenand_oob_64 - oob info for large (2KB) page
+ * onenand_oob_32_64 - oob info for large (2KB) page
*/
-static struct nand_ecclayout onenand_oob_64 = {
- .eccbytes = 20,
- .eccpos = {
- 8, 9, 10, 11, 12,
- 24, 25, 26, 27, 28,
- 40, 41, 42, 43, 44,
- 56, 57, 58, 59, 60,
- },
- .oobfree = {
- {2, 3}, {14, 2}, {18, 3}, {30, 2},
- {34, 3}, {46, 2}, {50, 3}, {62, 2}
+static int onenand_oob_32_64_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ int eccbytes = (mtd->oobsize / 32) * 10;
+
+ if (eccbyte >= eccbytes)
+ return -ERANGE;
+
+ return ((eccbyte / 5) * 16) + 8 + (eccbyte % 5);
+}
+
+static int onenand_oob_32_64_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ int sections = (mtd->oobsize / 32) * 2;
+
+ if (section >= sections)
+ return -ERANGE;
+
+ if (section & 1) {
+ oobfree->offset = ((section - 1) * 16) + 14;
+ oobfree->length = 2;
+ } else {
+ oobfree->offset = (section * 16) + 2;
+ oobfree->length = 3;
}
-};

-/**
- * onenand_oob_32 - oob info for middle (1KB) page
- */
-static struct nand_ecclayout onenand_oob_32 = {
- .eccbytes = 10,
- .eccpos = {
- 8, 9, 10, 11, 12,
- 24, 25, 26, 27, 28,
- },
- .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} }
+ return 0;
+}
+
+const struct mtd_ooblayout_ops onenand_oob_32_64_ooblayout_ops = {
+ .eccpos = onenand_oob_32_64_eccpos,
+ .oobfree = onenand_oob_32_64_oobfree,
};

static const unsigned char ffchars[] = {
@@ -4019,22 +4040,22 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
switch (mtd->oobsize) {
case 128:
if (FLEXONENAND(this)) {
- this->ecclayout = &flexonenand_oob_128;
+ mtd_set_ooblayout(mtd, &flexonenand_ooblayout_ops);
mtd->subpage_sft = 0;
} else {
- this->ecclayout = &onenand_oob_128;
+ mtd_set_ooblayout(mtd, &onenand_oob_128_ooblayout_ops);
mtd->subpage_sft = 2;
}
if (ONENAND_IS_NOP_1(this))
mtd->subpage_sft = 0;
break;
case 64:
- this->ecclayout = &onenand_oob_64;
+ mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
mtd->subpage_sft = 2;
break;

case 32:
- this->ecclayout = &onenand_oob_32;
+ mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
mtd->subpage_sft = 1;
break;

@@ -4043,7 +4064,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
__func__, mtd->oobsize);
mtd->subpage_sft = 0;
/* To prevent kernel oops */
- this->ecclayout = &onenand_oob_32;
+ mtd_set_ooblayout(mtd, &onenand_oob_32_64_ooblayout_ops);
break;
}

@@ -4059,7 +4080,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd_oobfree(mtd, i++, &oobfree))
mtd->oobavail += oobfree.length;

- mtd_set_ecclayout(mtd, this->ecclayout);
mtd->ecc_strength = 1;

/* Fill in remaining MTD driver data */
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 4596503..0aaa98b 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -80,7 +80,6 @@ struct onenand_bufferram {
* @page_buf: [INTERN] page main data buffer
* @oob_buf: [INTERN] page oob data buffer
* @subpagesize: [INTERN] holds the subpagesize
- * @ecclayout: [REPLACEABLE] the default ecc placement scheme
* @bbm: [REPLACEABLE] pointer to Bad Block Management
* @priv: [OPTIONAL] pointer to private chip date
*/
@@ -134,7 +133,6 @@ struct onenand_chip {
#endif

int subpagesize;
- struct nand_ecclayout *ecclayout;

void *bbm;

--
2.1.4

2015-12-07 22:27:59

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 21/23] staging: mt29f_spinand: switch to mtd_ooblayout_ops

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/staging/mt29f_spinand/mt29f_spinand.c | 44 ++++++++++++++++-----------
1 file changed, 26 insertions(+), 18 deletions(-)

diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index cb9d5ab..967d50a 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -42,23 +42,29 @@ static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd)
static int enable_hw_ecc;
static int enable_read_hw_ecc;

-static struct nand_ecclayout spinand_oob_64 = {
- .eccbytes = 24,
- .eccpos = {
- 1, 2, 3, 4, 5, 6,
- 17, 18, 19, 20, 21, 22,
- 33, 34, 35, 36, 37, 38,
- 49, 50, 51, 52, 53, 54, },
- .oobfree = {
- {.offset = 8,
- .length = 8},
- {.offset = 24,
- .length = 8},
- {.offset = 40,
- .length = 8},
- {.offset = 56,
- .length = 8},
- }
+static int spinand_oob_64_eccpos(struct mtd_info *mtd, int eccbyte)
+{
+ if (eccbyte > 23)
+ return -ERANGE;
+
+ return ((eccbyte / 6) * 16) + 1;
+}
+
+static int spinand_oob_64_oobfree(struct mtd_info *mtd, int section,
+ struct nand_oobfree *oobfree)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ oobfree->offset = (section * 16) + 8;
+ oobfree->length = 8;
+
+ return 0;
+}
+
+const struct mtd_ooblayout_ops spinand_oob_64_ops = {
+ .eccpos = spinand_oob_64_eccpos,
+ .oobfree = spinand_oob_64_oobfree,
};
#endif

@@ -883,7 +889,6 @@ static int spinand_probe(struct spi_device *spi_nand)

chip->ecc.strength = 1;
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
- chip->ecc.layout = &spinand_oob_64;
chip->ecc.read_page = spinand_read_page_hwecc;
chip->ecc.write_page = spinand_write_page_hwecc;
#else
@@ -911,6 +916,9 @@ static int spinand_probe(struct spi_device *spi_nand)
mtd->priv = chip;
mtd->dev.parent = &spi_nand->dev;
mtd->oobsize = 64;
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+ mtd_set_ooblayout(mtd, &spinand_oob_64_ops);
+#endif

if (nand_scan(mtd, 1))
return -ENXIO;
--
2.1.4

2015-12-07 22:28:02

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 22/23] mtd: nand: kill layout field

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/nand/nand_base.c | 8 --------
drivers/mtd/nand/nand_bch.c | 9 ---------
include/linux/mtd/nand.h | 1 -
3 files changed, 18 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 6440c5d..85deacb 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4148,13 +4148,6 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->oob_poi = chip->buffers->databuf + mtd->writesize;

/*
- * Set the provided ECC layout. If ecc->layout is NULL, the MTD core
- * will just leave mtd->ooblayout to NULL, if it's not NULL, it will
- * set ->ooblayout to the default ecclayout wrapper.
- */
- mtd_set_ecclayout(mtd, ecc->layout);
-
- /*
* If no default placement scheme is given, select an appropriate one.
*/
if (!mtd->ooblayout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
@@ -4401,7 +4394,6 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->writebufsize = mtd->writesize;

/* propagate ecc info to mtd_info */
- mtd_set_ecclayout(mtd, ecc->layout);
mtd->ecc_strength = ecc->strength;
mtd->ecc_step_size = ecc->size;
/*
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index 2937b49..3b90643 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -158,15 +158,6 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)

eccsteps = mtd->writesize/eccsize;

- /*
- * Rely on the default ecclayout to ooblayout wrapper provided by MTD
- * core if ecc.layout is not NULL.
- * FIXME: this should be removed when all callers have moved to the
- * mtd_ooblayout_ops approach.
- */
- if (nand->ecc.layout)
- mtd_set_ecclayout(mtd, nand->ecc.layout);
-
/* if no ecc placement scheme was provided, build one */
if (!mtd->ooblayout) {

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 9ba9daba..f4ba147 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -494,7 +494,6 @@ struct nand_ecc_ctrl {
int strength;
int prepad;
int postpad;
- struct nand_ecclayout *layout;
void *priv;
void (*hwctl)(struct mtd_info *mtd, int mode);
int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
--
2.1.4

2015-12-07 22:28:17

by Boris Brezillon

[permalink] [raw]
Subject: [PATCH 23/23] mtd: kill the nand_ecclayout struct

Now that all mtd drivers have moved to the mtd_ooblayout_ops model we can
safely remove the struct nand_ecclayout definition, and all the remaining
places where it was still used.

Signed-off-by: Boris Brezillon <[email protected]>
---
drivers/mtd/mtdchar.c | 12 ++++++------
drivers/mtd/mtdcore.c | 44 --------------------------------------------
include/linux/mtd/mtd.h | 20 --------------------
include/uapi/mtd/mtd-abi.h | 2 +-
4 files changed, 7 insertions(+), 71 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index c03b678..322e838 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -465,12 +465,12 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
}

/*
- * Copies (and truncates, if necessary) data from the larger struct,
- * nand_ecclayout, to the smaller, deprecated layout struct,
- * nand_ecclayout_user. This is necessary only to support the deprecated
- * API ioctl ECCGETLAYOUT while allowing all new functionality to use
- * nand_ecclayout flexibly (i.e. the struct may change size in new
- * releases without requiring major rewrites).
+ * Copies (and truncates, if necessary) OOB layout information to the
+ * deprecated layout struct, nand_ecclayout_user. This is necessary only to
+ * support the deprecated API ioctl ECCGETLAYOUT while allowing all new
+ * functionality to use mtd_ooblayout_ops flexibly (i.e. mtd_ooblayout_ops
+ * can describe any kind of OOB layout with almost zero overhead from a
+ * memory usage point of view).
*/
static int shrink_ecclayout(struct mtd_info *mtd,
struct nand_ecclayout_user *to)
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index d87f3621..62f83b0 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -833,50 +833,6 @@ void __put_mtd_device(struct mtd_info *mtd)
}
EXPORT_SYMBOL_GPL(__put_mtd_device);

-static int nand_ecclayout_eccpos(struct mtd_info *mtd, int eccbyte)
-{
- struct nand_ecclayout *layout = mtd->ecclayout;
-
- if (!layout)
- return -ENOTSUPP;
-
- if (eccbyte >= layout->eccbytes)
- return -ERANGE;
-
- return layout->eccpos[eccbyte];
-}
-
-static int nand_ecclayout_oobfree(struct mtd_info *mtd, int section,
- struct nand_oobfree *oobfree)
-{
- struct nand_ecclayout *layout = mtd->ecclayout;
-
- if (!layout)
- return -ENOTSUPP;
-
- if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE)
- return -ERANGE;
-
- *oobfree = layout->oobfree[section];
-
- return 0;
-}
-
-static const struct mtd_ooblayout_ops nand_ecclayout_ops = {
- .eccpos = nand_ecclayout_eccpos,
- .oobfree = nand_ecclayout_oobfree,
-};
-
-void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout)
-{
- if (!mtd || !ecclayout)
- return;
-
- mtd->ecclayout = ecclayout;
- mtd_set_ooblayout(mtd, &nand_ecclayout_ops);
-}
-EXPORT_SYMBOL_GPL(mtd_set_ecclayout);
-
/*
* Erase is an asynchronous operation. Device drivers are supposed
* to call instr->callback() whenever the operation completes, even
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 9c3699b..3a4bab7 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -96,21 +96,6 @@ struct mtd_oob_ops {

#define MTD_MAX_OOBFREE_ENTRIES_LARGE 32
#define MTD_MAX_ECCPOS_ENTRIES_LARGE 640
-/*
- * Internal ECC layout control structure. For historical reasons, there is a
- * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
- * for export to user-space via the ECCGETLAYOUT ioctl.
- * nand_ecclayout should be expandable in the future simply by the above macros.
- *
- * This structure is now deprecated, you should use struct nand_ecclayout_ops
- * to describe your OOB layout.
- */
-struct nand_ecclayout {
- __u32 eccbytes;
- __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
- struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
-};
-
/**
* struct mtd_ooblayout_ops - NAND OOB layout operations.
*
@@ -183,9 +168,6 @@ struct mtd_info {
const char *name;
int index;

- /* [Deprecated] ECC layout structure pointer - read only! */
- struct nand_ecclayout *ecclayout;
-
/* OOB layout description */
const struct mtd_ooblayout_ops *ooblayout;

@@ -279,8 +261,6 @@ static inline void mtd_set_ooblayout(struct mtd_info *mtd,
mtd->ooblayout = ooblayout;
}

-void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout);
-
static inline int mtd_eccpos(struct mtd_info *mtd, int eccbyte)
{
if (!mtd->ooblayout || !mtd->ooblayout->eccpos)
diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h
index 763bb69..0ec1da2 100644
--- a/include/uapi/mtd/mtd-abi.h
+++ b/include/uapi/mtd/mtd-abi.h
@@ -228,7 +228,7 @@ struct nand_oobfree {
* complete set of ECC information. The ioctl truncates the larger internal
* structure to retain binary compatibility with the static declaration of the
* ioctl. Note that the "MTD_MAX_..._ENTRIES" macros represent the max size of
- * the user struct, not the MAX size of the internal struct nand_ecclayout.
+ * the user struct, not the MAX size of the internal OOB layout representation.
*/
struct nand_ecclayout_user {
__u32 eccbytes;
--
2.1.4

2015-12-07 22:44:07

by Stefan Agner

[permalink] [raw]
Subject: Re: [PATCH 09/23] mtd: nand: vf610: remove useless mtd->ecclayout assignment

On 2015-12-07 14:26, Boris Brezillon wrote:
> The NAND core layer is already taking care of ecclayout propagation. Remove
> this useless assignment.

Thx! I see, nand_scan_tail takes care of that...

Acked-by: Stefan Agner <[email protected]>

>
> Signed-off-by: Boris Brezillon <[email protected]>
> ---
> drivers/mtd/nand/vf610_nfc.c | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
> index 1c86c6b..0413e24 100644
> --- a/drivers/mtd/nand/vf610_nfc.c
> +++ b/drivers/mtd/nand/vf610_nfc.c
> @@ -794,8 +794,6 @@ static int vf610_nfc_probe(struct platform_device *pdev)
> goto error;
> }
>
> - /* propagate ecc.layout to mtd_info */
> - mtd->ecclayout = chip->ecc.layout;
> chip->ecc.read_page = vf610_nfc_read_page;
> chip->ecc.write_page = vf610_nfc_write_page;

2015-12-07 22:50:15

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 12/23] mtd: use mtd_eccpos() and mtd_oobfree() where appropriate

Hi Boris,

[auto build test ERROR on next-20151207]
[cannot apply to staging/staging-testing v4.4-rc4 v4.4-rc3 v4.4-rc2 v4.4-rc4]

url: https://github.com/0day-ci/linux/commits/Boris-Brezillon/mtd-rework-ECC-layout-definition/20151208-063127
config: i386-randconfig-x006-12070758 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All error/warnings (new ones prefixed by >>):

In file included from include/linux/linkage.h:4:0,
from include/linux/kernel.h:6,
from drivers/mtd/mtdswap.c:27:
drivers/mtd/mtdswap.c: In function 'mtdswap_add_mtd':
>> drivers/mtd/mtdswap.c:1449:6: error: too few arguments to function 'mtd_oobfree'
if (mtd_oobfree(mtd, 0) < 0) {
^
include/linux/compiler.h:147:28: note: in definition of macro '__trace_if'
if (__builtin_constant_p((cond)) ? !!(cond) : \
^
>> drivers/mtd/mtdswap.c:1449:2: note: in expansion of macro 'if'
if (mtd_oobfree(mtd, 0) < 0) {
^
In file included from drivers/mtd/mtdswap.c:29:0:
include/linux/mtd/mtd.h:267:19: note: declared here
static inline int mtd_oobfree(struct mtd_info *mtd, int section,
^
In file included from include/linux/linkage.h:4:0,
from include/linux/kernel.h:6,
from drivers/mtd/mtdswap.c:27:
>> drivers/mtd/mtdswap.c:1449:6: error: too few arguments to function 'mtd_oobfree'
if (mtd_oobfree(mtd, 0) < 0) {
^
include/linux/compiler.h:147:40: note: in definition of macro '__trace_if'
if (__builtin_constant_p((cond)) ? !!(cond) : \
^
>> drivers/mtd/mtdswap.c:1449:2: note: in expansion of macro 'if'
if (mtd_oobfree(mtd, 0) < 0) {
^
In file included from drivers/mtd/mtdswap.c:29:0:
include/linux/mtd/mtd.h:267:19: note: declared here
static inline int mtd_oobfree(struct mtd_info *mtd, int section,
^
In file included from include/linux/linkage.h:4:0,
from include/linux/kernel.h:6,
from drivers/mtd/mtdswap.c:27:
>> drivers/mtd/mtdswap.c:1449:6: error: too few arguments to function 'mtd_oobfree'
if (mtd_oobfree(mtd, 0) < 0) {
^
include/linux/compiler.h:158:16: note: in definition of macro '__trace_if'
______r = !!(cond); \
^
>> drivers/mtd/mtdswap.c:1449:2: note: in expansion of macro 'if'
if (mtd_oobfree(mtd, 0) < 0) {
^
In file included from drivers/mtd/mtdswap.c:29:0:
include/linux/mtd/mtd.h:267:19: note: declared here
static inline int mtd_oobfree(struct mtd_info *mtd, int section,
^

vim +/mtd_oobfree +1449 drivers/mtd/mtdswap.c

1443 if (PAGE_SIZE % mtd->writesize || mtd->writesize > PAGE_SIZE) {
1444 printk(KERN_ERR "%s: PAGE_SIZE %lu not multiple of write size"
1445 " %u\n", MTDSWAP_PREFIX, PAGE_SIZE, mtd->writesize);
1446 return;
1447 }
1448
> 1449 if (mtd_oobfree(mtd, 0) < 0) {
1450 printk(KERN_ERR "%s: mtd%d does not have OOB\n",
1451 MTDSWAP_PREFIX, mtd->index);
1452 return;

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (3.29 kB)
.config.gz (25.73 kB)
Download all attachments

2015-12-07 23:01:59

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 22/23] mtd: nand: kill layout field

Hi Boris,

[auto build test ERROR on next-20151207]
[cannot apply to staging/staging-testing v4.4-rc4 v4.4-rc3 v4.4-rc2 v4.4-rc4]

url: https://github.com/0day-ci/linux/commits/Boris-Brezillon/mtd-rework-ECC-layout-definition/20151208-063127
config: powerpc-allyesconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=powerpc

All error/warnings (new ones prefixed by >>):

In file included from include/linux/printk.h:277:0,
from include/linux/kernel.h:13,
from include/linux/list.h:8,
from include/linux/module.h:9,
from drivers/mtd/nand/fsl_elbc_nand.c:25:
drivers/mtd/nand/fsl_elbc_nand.c: In function 'fsl_elbc_chip_init_tail':
>> drivers/mtd/nand/fsl_elbc_nand.c:683:19: error: 'struct nand_ecc_ctrl' has no member named 'layout'
chip->ecc.layout);
^
include/linux/dynamic_debug.h:87:9: note: in definition of macro 'dynamic_dev_dbg'
##__VA_ARGS__); \
^
>> drivers/mtd/nand/fsl_elbc_nand.c:682:2: note: in expansion of macro 'dev_dbg'
dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
^
drivers/mtd/nand/fsl_elbc_nand.c: In function 'fsl_elbc_chip_init':
drivers/mtd/nand/fsl_elbc_nand.c:797:34: error: 'fsl_elbc_ooblayout_op' undeclared (first use in this function)
mtd_set_ooblayout(&priv->mtd, &fsl_elbc_ooblayout_op);
^
drivers/mtd/nand/fsl_elbc_nand.c:797:34: note: each undeclared identifier is reported only once for each function it appears in

vim +683 drivers/mtd/nand/fsl_elbc_nand.c

3ab8f2a2 Roy Zang 2010-10-18 676 dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
76b10467 Scott Wood 2008-02-06 677 chip->ecc.steps);
3ab8f2a2 Roy Zang 2010-10-18 678 dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
76b10467 Scott Wood 2008-02-06 679 chip->ecc.bytes);
3ab8f2a2 Roy Zang 2010-10-18 680 dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
76b10467 Scott Wood 2008-02-06 681 chip->ecc.total);
3ab8f2a2 Roy Zang 2010-10-18 @682 dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
76b10467 Scott Wood 2008-02-06 @683 chip->ecc.layout);
3ab8f2a2 Roy Zang 2010-10-18 684 dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
3ab8f2a2 Roy Zang 2010-10-18 685 dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
3ab8f2a2 Roy Zang 2010-10-18 686 dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",

:::::: The code at line 683 was first introduced by commit
:::::: 76b104671632c225ad594a50f9e26ada67bc0a74 [MTD] [NAND] Freescale enhanced Local Bus Controller FCM NAND support.

:::::: TO: Scott Wood <[email protected]>
:::::: CC: David Woodhouse <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (3.17 kB)
.config.gz (46.54 kB)
Download all attachments

2015-12-07 23:38:04

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 12/23] mtd: use mtd_eccpos() and mtd_oobfree() where appropriate

Hi Boris,

[auto build test WARNING on next-20151207]
[cannot apply to staging/staging-testing v4.4-rc4 v4.4-rc3 v4.4-rc2 v4.4-rc4]

url: https://github.com/0day-ci/linux/commits/Boris-Brezillon/mtd-rework-ECC-layout-definition/20151208-063127
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

>> drivers/mtd/nand/nand_base.c:1607: warning: No description found for parameter 'mtd'
>> drivers/mtd/nand/nand_base.c:1607: warning: Excess function parameter 'chip' description in 'nand_transfer_oob'
>> drivers/mtd/nand/nand_base.c:1607: warning: No description found for parameter 'mtd'
>> drivers/mtd/nand/nand_base.c:1607: warning: Excess function parameter 'chip' description in 'nand_transfer_oob'

vim +/mtd +1607 drivers/mtd/nand/nand_base.c

7e4178f9 Vitaly Wool 2006-06-07 1591 i = mtd->oobsize - (oob - chip->oob_poi);
f5bbdacc Thomas Gleixner 2006-05-25 1592 if (i)
f5bbdacc Thomas Gleixner 2006-05-25 1593 chip->read_buf(mtd, oob, i);
f5bbdacc Thomas Gleixner 2006-05-25 1594
3f91e94f Mike Dunn 2012-04-25 1595 return max_bitflips;
^1da177e Linus Torvalds 2005-04-16 1596 }
^1da177e Linus Torvalds 2005-04-16 1597
f5bbdacc Thomas Gleixner 2006-05-25 1598 /**
7854d3f7 Brian Norris 2011-06-23 1599 * nand_transfer_oob - [INTERN] Transfer oob to client buffer
8593fbc6 Thomas Gleixner 2006-05-29 1600 * @chip: nand chip structure
844d3b42 Randy Dunlap 2006-06-28 1601 * @oob: oob destination address
8593fbc6 Thomas Gleixner 2006-05-29 1602 * @ops: oob ops structure
7014568b Vitaly Wool 2006-11-03 1603 * @len: size of oob to transfer
8593fbc6 Thomas Gleixner 2006-05-29 1604 */
64456fac Boris Brezillon 2015-12-07 1605 static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
7014568b Vitaly Wool 2006-11-03 1606 struct mtd_oob_ops *ops, size_t len)
8593fbc6 Thomas Gleixner 2006-05-29 @1607 {
64456fac Boris Brezillon 2015-12-07 1608 struct nand_chip *chip = mtd->priv;
64456fac Boris Brezillon 2015-12-07 1609
8593fbc6 Thomas Gleixner 2006-05-29 1610 switch (ops->mode) {
8593fbc6 Thomas Gleixner 2006-05-29 1611
0612b9dd Brian Norris 2011-08-30 1612 case MTD_OPS_PLACE_OOB:
0612b9dd Brian Norris 2011-08-30 1613 case MTD_OPS_RAW:
8593fbc6 Thomas Gleixner 2006-05-29 1614 memcpy(oob, chip->oob_poi + ops->ooboffs, len);
8593fbc6 Thomas Gleixner 2006-05-29 1615 return oob + len;

:::::: The code at line 1607 was first introduced by commit
:::::: 8593fbc68b0df1168995de76d1af38eb62fd6b62 [MTD] Rework the out of band handling completely

:::::: TO: Thomas Gleixner <[email protected]>
:::::: CC: Thomas Gleixner <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (2.81 kB)
.config.gz (6.02 kB)
Download all attachments

2015-12-08 00:00:15

by Julian Calaby

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH 21/23] staging: mt29f_spinand: switch to mtd_ooblayout_ops

Hi Boris,

On Tue, Dec 8, 2015 at 9:26 AM, Boris Brezillon
<[email protected]> wrote:
> Signed-off-by: Boris Brezillon <[email protected]>
> ---
> drivers/staging/mt29f_spinand/mt29f_spinand.c | 44 ++++++++++++++++-----------
> 1 file changed, 26 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
> index cb9d5ab..967d50a 100644
> --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
> +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
> @@ -42,23 +42,29 @@ static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd)
> static int enable_hw_ecc;
> static int enable_read_hw_ecc;
>
> -static struct nand_ecclayout spinand_oob_64 = {
> - .eccbytes = 24,
> - .eccpos = {
> - 1, 2, 3, 4, 5, 6,
> - 17, 18, 19, 20, 21, 22,
> - 33, 34, 35, 36, 37, 38,
> - 49, 50, 51, 52, 53, 54, },
> - .oobfree = {
> - {.offset = 8,
> - .length = 8},
> - {.offset = 24,
> - .length = 8},
> - {.offset = 40,
> - .length = 8},
> - {.offset = 56,
> - .length = 8},
> - }
> +static int spinand_oob_64_eccpos(struct mtd_info *mtd, int eccbyte)
> +{
> + if (eccbyte > 23)
> + return -ERANGE;
> +
> + return ((eccbyte / 6) * 16) + 1;

Are you sure this is correct? My reading of this is that we'd get 1
for eccbytes 0 through 5.

Would

((eccbyte / 6) * 16) + (eccbyte % 6) + 1

be more correct?

Thanks,

--
Julian Calaby

Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/

2015-12-08 00:38:58

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 04/23] mtd: nand: s3c2410: kill the ->ecc_layout field

On 08.12.2015 07:25, Boris Brezillon wrote:
> The s3c2410 is allowing board data to overload the default ECC layout
> defined inside the driver, but this feature is not used by board
> specific definitions.
> Kill this field so that we can easily move to a model where ecclayout
> are dynamically allocated by the NAND controller driver.
>
> Signed-off-by: Boris Brezillon <[email protected]>
> ---
> arch/arm/plat-samsung/devs.c | 9 ---------
> drivers/mtd/nand/s3c2410.c | 3 ---
> include/linux/platform_data/mtd-nand-s3c2410.h | 1 -
> 3 files changed, 13 deletions(-)

Acked-by: Krzysztof Kozlowski <[email protected]>

Best regards,
Krzysztof


2015-12-08 06:43:11

by Priit Laes

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH 01/23] mtd: kill the ecclayout->oobavail field

On Mon, 2015-12-07 at 23:25 +0100, Boris Brezillon wrote:
> ecclayout->oobavail is just redundant with the mtd->oobavail field.
> Moreover, it prevents static const definition of ecc layouts since
> the
> NAND framework is calculating this value based on the ecclayout-
> >oobfree
> field.
>
> Signed-off-by: Boris Brezillon <[email protected]>
> ---
>  drivers/mtd/devices/docg3.c                   |  5 ++-
>  drivers/mtd/mtdswap.c                         | 16 ++++-----
>  drivers/mtd/nand/brcmnand/brcmnand.c          |  3 --
>  drivers/mtd/nand/docg4.c                      |  1 -
>  drivers/mtd/nand/hisi504_nand.c               |  1 -
>  drivers/mtd/nand/nand_base.c                  | 12 +++----
>  drivers/mtd/onenand/onenand_base.c            | 16 ++++-----
>  drivers/mtd/tests/oobtest.c                   | 49 +++++++++++++--
> ------------
>  drivers/staging/mt29f_spinand/mt29f_spinand.c |  1 -
>  fs/jffs2/wbuf.c                               |  6 ++--
>  include/linux/mtd/mtd.h                       |  1 -
>  11 files changed, 48 insertions(+), 63 deletions(-)
>
[..]
>  
> diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c
> b/drivers/mtd/nand/brcmnand/brcmnand.c
> index 35d78f7..a906ec2 100644
> --- a/drivers/mtd/nand/brcmnand/brcmnand.c
> +++ b/drivers/mtd/nand/brcmnand/brcmnand.c
> @@ -845,9 +845,6 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
>   break;
>   }
>  out:
> - /* Sum available OOB */
> - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE; i++)
> - layout->oobavail += layout->oobfree[i].length;
>   return layout;
>  }

You can get rid of the 'out' label and replace the single goto in this
function with 'return layout'.

[...]
>  
> diff --git a/drivers/mtd/nand/nand_base.c
> b/drivers/mtd/nand/nand_base.c
> index 0748a13..1107f5c1 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -2037,7 +2037,7 @@ static int nand_do_read_oob(struct mtd_info
> *mtd, loff_t from,
>   stats = mtd->ecc_stats;
>  
>   if (ops->mode == MTD_OPS_AUTO_OOB)
> - len = chip->ecc.layout->oobavail;
> + len = mtd->oobavail;
>   else
>   len = mtd->oobsize;
>  
> @@ -2728,7 +2728,7 @@ static int nand_do_write_oob(struct mtd_info
> *mtd, loff_t to,
>    __func__, (unsigned int)to, (int)ops-
> >ooblen);
>  
>   if (ops->mode == MTD_OPS_AUTO_OOB)
> - len = chip->ecc.layout->oobavail;
> + len = mtd->oobavail;
>   else
>   len = mtd->oobsize;
>  
[...]
> diff --git a/drivers/mtd/onenand/onenand_base.c
> b/drivers/mtd/onenand/onenand_base.c
> index 43b3392..d70bbfd 100644
> --- a/drivers/mtd/onenand/onenand_base.c
> +++ b/drivers/mtd/onenand/onenand_base.c
> @@ -1125,7 +1125,7 @@ static int onenand_mlc_read_ops_nolock(struct
> mtd_info *mtd, loff_t from,
>   (int)len);
>  
>   if (ops->mode == MTD_OPS_AUTO_OOB)
> - oobsize = this->ecclayout->oobavail;
> + oobsize = mtd->oobavail;
>   else
>   oobsize = mtd->oobsize;
>  
> @@ -1230,7 +1230,7 @@ static int onenand_read_ops_nolock(struct
> mtd_info *mtd, loff_t from,
>   (int)len);
>  
>   if (ops->mode == MTD_OPS_AUTO_OOB)
> - oobsize = this->ecclayout->oobavail;
> + oobsize = mtd->oobavail;
>   else
>   oobsize = mtd->oobsize;
>  
> @@ -1365,7 +1365,7 @@ static int onenand_read_oob_nolock(struct
> mtd_info *mtd, loff_t from,
>   ops->oobretlen = 0;
>  
>   if (mode == MTD_OPS_AUTO_OOB)
> - oobsize = this->ecclayout->oobavail;
> + oobsize = mtd->oobavail;
>   else
>   oobsize = mtd->oobsize;
>  
> @@ -1887,7 +1887,7 @@ static int onenand_write_ops_nolock(struct
> mtd_info *mtd, loff_t to,
>   return 0;
>  
>   if (ops->mode == MTD_OPS_AUTO_OOB)
> - oobsize = this->ecclayout->oobavail;
> + oobsize = mtd->oobavail;
>   else
>   oobsize = mtd->oobsize;
>  
> @@ -2063,7 +2063,7 @@ static int onenand_write_oob_nolock(struct
> mtd_info *mtd, loff_t to,
>   ops->oobretlen = 0;
>  
>   if (mode == MTD_OPS_AUTO_OOB)
> - oobsize = this->ecclayout->oobavail;
> + oobsize = mtd->oobavail;
>   else
>   oobsize = mtd->oobsize;

This identical construction seems to occur multiple times in multiple
files. Would it make sense to create a macro for it?


Päikest,
Priit Laes :)

2015-12-08 08:15:01

by Boris Brezillon

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH 01/23] mtd: kill the ecclayout->oobavail field

Hi Priit,

On Tue, 08 Dec 2015 08:43:05 +0200
Priit Laes <[email protected]> wrote:

> On Mon, 2015-12-07 at 23:25 +0100, Boris Brezillon wrote:
> > ecclayout->oobavail is just redundant with the mtd->oobavail field.
> > Moreover, it prevents static const definition of ecc layouts since
> > the
> > NAND framework is calculating this value based on the ecclayout-
> > >oobfree
> > field.
> >
> > Signed-off-by: Boris Brezillon <[email protected]>
> > ---
> >  drivers/mtd/devices/docg3.c                   |  5 ++-
> >  drivers/mtd/mtdswap.c                         | 16 ++++-----
> >  drivers/mtd/nand/brcmnand/brcmnand.c          |  3 --
> >  drivers/mtd/nand/docg4.c                      |  1 -
> >  drivers/mtd/nand/hisi504_nand.c               |  1 -
> >  drivers/mtd/nand/nand_base.c                  | 12 +++----
> >  drivers/mtd/onenand/onenand_base.c            | 16 ++++-----
> >  drivers/mtd/tests/oobtest.c                   | 49 +++++++++++++--
> > ------------
> >  drivers/staging/mt29f_spinand/mt29f_spinand.c |  1 -
> >  fs/jffs2/wbuf.c                               |  6 ++--
> >  include/linux/mtd/mtd.h                       |  1 -
> >  11 files changed, 48 insertions(+), 63 deletions(-)
> >
> [..]
> >  
> > diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c
> > b/drivers/mtd/nand/brcmnand/brcmnand.c
> > index 35d78f7..a906ec2 100644
> > --- a/drivers/mtd/nand/brcmnand/brcmnand.c
> > +++ b/drivers/mtd/nand/brcmnand/brcmnand.c
> > @@ -845,9 +845,6 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
> >   break;
> >   }
> >  out:
> > - /* Sum available OOB */
> > - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE; i++)
> > - layout->oobavail += layout->oobfree[i].length;
> >   return layout;
> >  }
>
> You can get rid of the 'out' label and replace the single goto in this
> function with 'return layout'.

Yep, I'll fix that.

>
> [...]
> >  
> > diff --git a/drivers/mtd/nand/nand_base.c
> > b/drivers/mtd/nand/nand_base.c
> > index 0748a13..1107f5c1 100644
> > --- a/drivers/mtd/nand/nand_base.c
> > +++ b/drivers/mtd/nand/nand_base.c
> > @@ -2037,7 +2037,7 @@ static int nand_do_read_oob(struct mtd_info
> > *mtd, loff_t from,
> >   stats = mtd->ecc_stats;
> >  
> >   if (ops->mode == MTD_OPS_AUTO_OOB)
> > - len = chip->ecc.layout->oobavail;
> > + len = mtd->oobavail;
> >   else
> >   len = mtd->oobsize;
> >  
> > @@ -2728,7 +2728,7 @@ static int nand_do_write_oob(struct mtd_info
> > *mtd, loff_t to,
> >    __func__, (unsigned int)to, (int)ops-
> > >ooblen);
> >  
> >   if (ops->mode == MTD_OPS_AUTO_OOB)
> > - len = chip->ecc.layout->oobavail;
> > + len = mtd->oobavail;
> >   else
> >   len = mtd->oobsize;
> >  
> [...]
> > diff --git a/drivers/mtd/onenand/onenand_base.c
> > b/drivers/mtd/onenand/onenand_base.c
> > index 43b3392..d70bbfd 100644
> > --- a/drivers/mtd/onenand/onenand_base.c
> > +++ b/drivers/mtd/onenand/onenand_base.c
> > @@ -1125,7 +1125,7 @@ static int onenand_mlc_read_ops_nolock(struct
> > mtd_info *mtd, loff_t from,
> >   (int)len);
> >  
> >   if (ops->mode == MTD_OPS_AUTO_OOB)
> > - oobsize = this->ecclayout->oobavail;
> > + oobsize = mtd->oobavail;
> >   else
> >   oobsize = mtd->oobsize;
> >  
> > @@ -1230,7 +1230,7 @@ static int onenand_read_ops_nolock(struct
> > mtd_info *mtd, loff_t from,
> >   (int)len);
> >  
> >   if (ops->mode == MTD_OPS_AUTO_OOB)
> > - oobsize = this->ecclayout->oobavail;
> > + oobsize = mtd->oobavail;
> >   else
> >   oobsize = mtd->oobsize;
> >  
> > @@ -1365,7 +1365,7 @@ static int onenand_read_oob_nolock(struct
> > mtd_info *mtd, loff_t from,
> >   ops->oobretlen = 0;
> >  
> >   if (mode == MTD_OPS_AUTO_OOB)
> > - oobsize = this->ecclayout->oobavail;
> > + oobsize = mtd->oobavail;
> >   else
> >   oobsize = mtd->oobsize;
> >  
> > @@ -1887,7 +1887,7 @@ static int onenand_write_ops_nolock(struct
> > mtd_info *mtd, loff_t to,
> >   return 0;
> >  
> >   if (ops->mode == MTD_OPS_AUTO_OOB)
> > - oobsize = this->ecclayout->oobavail;
> > + oobsize = mtd->oobavail;
> >   else
> >   oobsize = mtd->oobsize;
> >  
> > @@ -2063,7 +2063,7 @@ static int onenand_write_oob_nolock(struct
> > mtd_info *mtd, loff_t to,
> >   ops->oobretlen = 0;
> >  
> >   if (mode == MTD_OPS_AUTO_OOB)
> > - oobsize = this->ecclayout->oobavail;
> > + oobsize = mtd->oobavail;
> >   else
> >   oobsize = mtd->oobsize;
>
> This identical construction seems to occur multiple times in multiple
> files. Would it make sense to create a macro for it?

Right, I'll make another patch move this logic into an inline function.

Thanks for the review.

Boris


--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

2015-12-08 08:44:09

by Boris Brezillon

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH 21/23] staging: mt29f_spinand: switch to mtd_ooblayout_ops

Hi Julian,

On Tue, 8 Dec 2015 10:59:53 +1100
Julian Calaby <[email protected]> wrote:

> Hi Boris,
>
> On Tue, Dec 8, 2015 at 9:26 AM, Boris Brezillon
> <[email protected]> wrote:
> > Signed-off-by: Boris Brezillon <[email protected]>
> > ---
> > drivers/staging/mt29f_spinand/mt29f_spinand.c | 44 ++++++++++++++++-----------
> > 1 file changed, 26 insertions(+), 18 deletions(-)
> >
> > diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
> > index cb9d5ab..967d50a 100644
> > --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
> > +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
> > @@ -42,23 +42,29 @@ static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd)
> > static int enable_hw_ecc;
> > static int enable_read_hw_ecc;
> >
> > -static struct nand_ecclayout spinand_oob_64 = {
> > - .eccbytes = 24,
> > - .eccpos = {
> > - 1, 2, 3, 4, 5, 6,
> > - 17, 18, 19, 20, 21, 22,
> > - 33, 34, 35, 36, 37, 38,
> > - 49, 50, 51, 52, 53, 54, },
> > - .oobfree = {
> > - {.offset = 8,
> > - .length = 8},
> > - {.offset = 24,
> > - .length = 8},
> > - {.offset = 40,
> > - .length = 8},
> > - {.offset = 56,
> > - .length = 8},
> > - }
> > +static int spinand_oob_64_eccpos(struct mtd_info *mtd, int eccbyte)
> > +{
> > + if (eccbyte > 23)
> > + return -ERANGE;
> > +
> > + return ((eccbyte / 6) * 16) + 1;
>
> Are you sure this is correct? My reading of this is that we'd get 1
> for eccbytes 0 through 5.
>
> Would
>
> ((eccbyte / 6) * 16) + (eccbyte % 6) + 1
>
> be more correct?

Absolutely. I'll fix that.

Thanks,

Boris

--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

2015-12-08 10:11:48

by Ralf Baechle

[permalink] [raw]
Subject: Re: [PATCH 19/23] mtd: nand: switch all drivers to mtd_ooblayout_ops

On Mon, Dec 07, 2015 at 11:26:14PM +0100, Boris Brezillon wrote:

Looking good,

Acked-by: Ralf Baechle <[email protected]>

Ralf

2015-12-08 10:31:01

by Harvey Hunt

[permalink] [raw]
Subject: Re: [PATCH 05/23] mtd: nand: jz4770: kill the ->ecc_layout field

Hi Boris,

On 07/12/15 22:26, Boris Brezillon wrote:
> ->ecc_layout is not used by any board file. Kill this field to avoid any
> confusion. New boards are encouraged to use the default ECC layout defined
> in NAND core.
>
> Signed-off-by: Boris Brezillon <[email protected]>
> ---
> arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 2 --
> drivers/mtd/nand/jz4740_nand.c | 3 ---
> 2 files changed, 5 deletions(-)
>
> diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
> index 79cff26..398733e 100644
> --- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
> +++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
> @@ -25,8 +25,6 @@ struct jz_nand_platform_data {
> int num_partitions;
> struct mtd_partition *partitions;
>
> - struct nand_ecclayout *ecc_layout;
> -
> unsigned char banks[JZ_NAND_NUM_BANKS];
>
> void (*ident_callback)(struct platform_device *, struct nand_chip *,
> diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
> index 5a99a93..c4fe446 100644
> --- a/drivers/mtd/nand/jz4740_nand.c
> +++ b/drivers/mtd/nand/jz4740_nand.c
> @@ -446,9 +446,6 @@ static int jz_nand_probe(struct platform_device *pdev)
> chip->ecc.bytes = 9;
> chip->ecc.strength = 4;
>
> - if (pdata)
> - chip->ecc.layout = pdata->ecc_layout;
> -
> chip->chip_delay = 50;
> chip->cmd_ctrl = jz_nand_cmd_ctrl;
> chip->select_chip = jz_nand_select_chip;
>

Is there a typo in this commit title? The JZ4740 and JZ4770 have quite
different NAND controller interfaces, so I don't think that the JZ4740
driver will support the JZ4770.

Thanks,

Harvey

2015-12-08 10:33:50

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH 05/23] mtd: nand: jz4770: kill the ->ecc_layout field

On Tue, 8 Dec 2015 10:30:40 +0000
Harvey Hunt <[email protected]> wrote:

> Hi Boris,
>
> On 07/12/15 22:26, Boris Brezillon wrote:
> > ->ecc_layout is not used by any board file. Kill this field to avoid any
> > confusion. New boards are encouraged to use the default ECC layout defined
> > in NAND core.
> >
> > Signed-off-by: Boris Brezillon <[email protected]>
> > ---
> > arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 2 --
> > drivers/mtd/nand/jz4740_nand.c | 3 ---
> > 2 files changed, 5 deletions(-)
> >
> > diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
> > index 79cff26..398733e 100644
> > --- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
> > +++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
> > @@ -25,8 +25,6 @@ struct jz_nand_platform_data {
> > int num_partitions;
> > struct mtd_partition *partitions;
> >
> > - struct nand_ecclayout *ecc_layout;
> > -
> > unsigned char banks[JZ_NAND_NUM_BANKS];
> >
> > void (*ident_callback)(struct platform_device *, struct nand_chip *,
> > diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
> > index 5a99a93..c4fe446 100644
> > --- a/drivers/mtd/nand/jz4740_nand.c
> > +++ b/drivers/mtd/nand/jz4740_nand.c
> > @@ -446,9 +446,6 @@ static int jz_nand_probe(struct platform_device *pdev)
> > chip->ecc.bytes = 9;
> > chip->ecc.strength = 4;
> >
> > - if (pdata)
> > - chip->ecc.layout = pdata->ecc_layout;
> > -
> > chip->chip_delay = 50;
> > chip->cmd_ctrl = jz_nand_cmd_ctrl;
> > chip->select_chip = jz_nand_select_chip;
> >
>
> Is there a typo in this commit title? The JZ4740 and JZ4770 have quite
> different NAND controller interfaces, so I don't think that the JZ4740
> driver will support the JZ4770.

Yes, it's a typo, I meant jz4740, I'll fix my commit message
accordingly.

Thanks,

Boris

--
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com