[RFC PATCH] mtd: add per NAND partition ECC config

Boris BREZILLON b.brezillon.dev at gmail.com
Mon Feb 10 13:11:49 EST 2014


On 08/02/2014 11:26, Boris BREZILLON wrote:
> This patch aims to add per partition ECC config for NAND devices.
> It defines a new field in the mtd struct to store the mtd ECC config and
> thus each mtd partition device can store its config instead of using the
> default NAND chip config.
>
> This feature is needed to support the sunxi boot0 paritition case:
> Allwinner boot code (BROM) requires a specific HW ECC for its boot code
> that may not fit the HW NAND requirements for the entire NAND chip.
>
> Signed-off-by: Boris BREZILLON <b.brezillon.dev at gmail.com>
> ---
> Hello,
>
> This patch is just a draft that implement per partition ECC config.
> It's currently not properly splitted (it should be separated in several
> patches) and not documented either.
>
> There's at least one point that bother me in the current implementation:
> I introduced DT notions in the nand core code by the mean of the get_ecc_ctrl
> callback, and so far this was kept out of mtd/nand core code (I guess it was
> on purpose).
>
> Please let me know if you see other drawbacks.
>
> If you think per partition ECC should not be implemented, could you help me
> find a way to handle sunxi specific case decribed above ?

My bad, this does not work properly: the  eccctrl defined in mtd slaves 
are never used
because the mtd part_xx functions pass the master mtd struct to the NAND 
framework.

> Best Regards,
>
> Boris
>
>
>
>
>   drivers/mtd/mtdpart.c          |   23 ++-
>   drivers/mtd/nand/nand_base.c   |  428 ++++++++++++++++++++++++----------------
>   drivers/mtd/ofpart.c           |   35 ++++
>   include/linux/mtd/mtd.h        |    3 +
>   include/linux/mtd/nand.h       |   12 ++
>   include/linux/mtd/partitions.h |    1 +
>   6 files changed, 332 insertions(+), 170 deletions(-)
>
> diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
> index 6e732c3..a5e262a 100644
> --- a/drivers/mtd/mtdpart.c
> +++ b/drivers/mtd/mtdpart.c
> @@ -28,6 +28,7 @@
>   #include <linux/list.h>
>   #include <linux/kmod.h>
>   #include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
>   #include <linux/mtd/partitions.h>
>   #include <linux/err.h>
>   
> @@ -310,6 +311,8 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
>   static inline void free_partition(struct mtd_part *p)
>   {
>   	kfree(p->mtd.name);
> +	if (p->mtd.eccctrl && p->mtd.eccctrl->release)
> +		p->mtd.eccctrl->release(p->mtd.eccctrl);
>   	kfree(p);
>   }
>   
> @@ -364,7 +367,13 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
>   	slave->mtd.writesize = master->writesize;
>   	slave->mtd.writebufsize = master->writebufsize;
>   	slave->mtd.oobsize = master->oobsize;
> -	slave->mtd.oobavail = master->oobavail;
> +	if (part->eccctrl) {
> +		slave->mtd.eccctrl = part->eccctrl;
> +		slave->mtd.oobavail = part->eccctrl->layout->oobavail;
> +	} else {
> +		slave->mtd.eccctrl = master->eccctrl;
> +		slave->mtd.oobavail = master->oobavail;
> +	}
>   	slave->mtd.subpage_sft = master->subpage_sft;
>   
>   	slave->mtd.name = name;
> @@ -515,9 +524,15 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
>   			part->name);
>   	}
>   
> -	slave->mtd.ecclayout = master->ecclayout;
> -	slave->mtd.ecc_step_size = master->ecc_step_size;
> -	slave->mtd.ecc_strength = master->ecc_strength;
> +	if (part->eccctrl) {
> +		slave->mtd.ecclayout = part->eccctrl->layout;
> +		slave->mtd.ecc_step_size = part->eccctrl->size;
> +		slave->mtd.ecc_strength = part->eccctrl->strength;
> +	} else {
> +		slave->mtd.ecclayout = 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;
>   
>   	if (master->_block_isbad) {
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index f59a465..24c1571 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -45,6 +45,7 @@
>   #include <linux/leds.h>
>   #include <linux/io.h>
>   #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 = {
> @@ -1031,26 +1032,26 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
>   				       struct nand_chip *chip, uint8_t *buf,
>   				       int oob_required, int page)
>   {
> -	int eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> +	int eccsize = mtd->eccctrl->size;
> +	int eccbytes = mtd->eccctrl->bytes;
>   	uint8_t *oob = chip->oob_poi;
>   	int steps, size;
>   
> -	for (steps = chip->ecc.steps; steps > 0; steps--) {
> +	for (steps = mtd->eccctrl->steps; steps > 0; steps--) {
>   		chip->read_buf(mtd, buf, eccsize);
>   		buf += eccsize;
>   
> -		if (chip->ecc.prepad) {
> -			chip->read_buf(mtd, oob, chip->ecc.prepad);
> -			oob += chip->ecc.prepad;
> +		if (mtd->eccctrl->prepad) {
> +			chip->read_buf(mtd, oob, mtd->eccctrl->prepad);
> +			oob += mtd->eccctrl->prepad;
>   		}
>   
>   		chip->read_buf(mtd, oob, eccbytes);
>   		oob += eccbytes;
>   
> -		if (chip->ecc.postpad) {
> -			chip->read_buf(mtd, oob, chip->ecc.postpad);
> -			oob += chip->ecc.postpad;
> +		if (mtd->eccctrl->postpad) {
> +			chip->read_buf(mtd, oob, mtd->eccctrl->postpad);
> +			oob += mtd->eccctrl->postpad;
>   		}
>   	}
>   
> @@ -1072,30 +1073,31 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
>   static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
>   				uint8_t *buf, int oob_required, int page)
>   {
> -	int i, eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> -	int eccsteps = chip->ecc.steps;
> +	int i, eccsize = mtd->eccctrl->size;
> +	int eccbytes = mtd->eccctrl->bytes;
> +	int eccsteps = mtd->eccctrl->steps;
>   	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;
> +	uint32_t *eccpos = mtd->eccctrl->layout->eccpos;
>   	unsigned int max_bitflips = 0;
>   
> -	chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
> +	mtd->eccctrl->read_page_raw(mtd, chip, buf, 1, page);
>   
>   	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> -		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
> +		mtd->eccctrl->calculate(mtd, p, &ecc_calc[i]);
>   
> -	for (i = 0; i < chip->ecc.total; i++)
> +	for (i = 0; i < mtd->eccctrl->total; i++)
>   		ecc_code[i] = chip->oob_poi[eccpos[i]];
>   
> -	eccsteps = chip->ecc.steps;
> +	eccsteps = mtd->eccctrl->steps;
>   	p = buf;
>   
>   	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
>   		int stat;
>   
> -		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
> +		stat = mtd->eccctrl->correct(mtd, p, &ecc_code[i],
> +					     &ecc_calc[i]);
>   		if (stat < 0) {
>   			mtd->ecc_stats.failed++;
>   		} else {
> @@ -1118,7 +1120,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
>   			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
>   {
>   	int start_step, end_step, num_steps;
> -	uint32_t *eccpos = chip->ecc.layout->eccpos;
> +	uint32_t *eccpos = mtd->eccctrl->layout->eccpos;
>   	uint8_t *p;
>   	int data_col_addr, i, gaps = 0;
>   	int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
> @@ -1127,15 +1129,15 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
>   	unsigned int max_bitflips = 0;
>   
>   	/* Column address within the page aligned to ECC size (256bytes) */
> -	start_step = data_offs / chip->ecc.size;
> -	end_step = (data_offs + readlen - 1) / chip->ecc.size;
> +	start_step = data_offs / mtd->eccctrl->size;
> +	end_step = (data_offs + readlen - 1) / mtd->eccctrl->size;
>   	num_steps = end_step - start_step + 1;
>   
>   	/* Data size aligned to ECC ecc.size */
> -	datafrag_len = num_steps * chip->ecc.size;
> -	eccfrag_len = num_steps * chip->ecc.bytes;
> +	datafrag_len = num_steps * mtd->eccctrl->size;
> +	eccfrag_len = num_steps * mtd->eccctrl->bytes;
>   
> -	data_col_addr = start_step * chip->ecc.size;
> +	data_col_addr = start_step * mtd->eccctrl->size;
>   	/* If we read not a page aligned data */
>   	if (data_col_addr != 0)
>   		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
> @@ -1144,16 +1146,17 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
>   	chip->read_buf(mtd, p, datafrag_len);
>   
>   	/* Calculate ECC */
> -	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
> -		chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);
> +	for (i = 0; i < eccfrag_len;
> +	     i += mtd->eccctrl->bytes, p += mtd->eccctrl->size)
> +		mtd->eccctrl->calculate(mtd, p, &chip->buffers->ecccalc[i]);
>   
>   	/*
>   	 * The performance is faster if we position offsets according to
>   	 * 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 + start_step * chip->ecc.bytes] + 1 !=
> -			eccpos[i + start_step * chip->ecc.bytes + 1]) {
> +		if (eccpos[i + start_step * mtd->eccctrl->bytes] + 1 !=
> +			eccpos[i + start_step * mtd->eccctrl->bytes + 1]) {
>   			gaps = 1;
>   			break;
>   		}
> @@ -1166,13 +1169,14 @@ 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.
>   		 */
> -		index = start_step * chip->ecc.bytes;
> +		index = start_step * mtd->eccctrl->bytes;
>   
>   		aligned_pos = eccpos[index] & ~(busw - 1);
>   		aligned_len = eccfrag_len;
>   		if (eccpos[index] & (busw - 1))
>   			aligned_len++;
> -		if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
> +		if (eccpos[index + (num_steps * mtd->eccctrl->bytes)] &
> +		    (busw - 1))
>   			aligned_len++;
>   
>   		chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
> @@ -1184,11 +1188,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
>   		chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]];
>   
>   	p = bufpoi + data_col_addr;
> -	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
> +	for (i = 0; i < eccfrag_len;
> +	     i += mtd->eccctrl->bytes, p += mtd->eccctrl->size) {
>   		int stat;
>   
> -		stat = chip->ecc.correct(mtd, p,
> -			&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
> +		stat = mtd->eccctrl->correct(mtd, p,
> +					     &chip->buffers->ecccode[i],
> +					     &chip->buffers->ecccalc[i]);
>   		if (stat < 0) {
>   			mtd->ecc_stats.failed++;
>   		} else {
> @@ -1212,32 +1218,33 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
>   static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
>   				uint8_t *buf, int oob_required, int page)
>   {
> -	int i, eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> -	int eccsteps = chip->ecc.steps;
> +	int i, eccsize = mtd->eccctrl->size;
> +	int eccbytes = mtd->eccctrl->bytes;
> +	int eccsteps = mtd->eccctrl->steps;
>   	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;
> +	uint32_t *eccpos = mtd->eccctrl->layout->eccpos;
>   	unsigned int max_bitflips = 0;
>   
>   	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
> -		chip->ecc.hwctl(mtd, NAND_ECC_READ);
> +		mtd->eccctrl->hwctl(mtd, NAND_ECC_READ);
>   		chip->read_buf(mtd, p, eccsize);
> -		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
> +		mtd->eccctrl->calculate(mtd, p, &ecc_calc[i]);
>   	}
>   	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
>   
> -	for (i = 0; i < chip->ecc.total; i++)
> +	for (i = 0; i < mtd->eccctrl->total; i++)
>   		ecc_code[i] = chip->oob_poi[eccpos[i]];
>   
> -	eccsteps = chip->ecc.steps;
> +	eccsteps = mtd->eccctrl->steps;
>   	p = buf;
>   
>   	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
>   		int stat;
>   
> -		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
> +		stat = mtd->eccctrl->correct(mtd, p, &ecc_code[i],
> +					     &ecc_calc[i]);
>   		if (stat < 0) {
>   			mtd->ecc_stats.failed++;
>   		} else {
> @@ -1265,12 +1272,12 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
>   static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
>   	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
>   {
> -	int i, eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> -	int eccsteps = chip->ecc.steps;
> +	int i, eccsize = mtd->eccctrl->size;
> +	int eccbytes = mtd->eccctrl->bytes;
> +	int eccsteps = mtd->eccctrl->steps;
>   	uint8_t *p = buf;
>   	uint8_t *ecc_code = chip->buffers->ecccode;
> -	uint32_t *eccpos = chip->ecc.layout->eccpos;
> +	uint32_t *eccpos = mtd->eccctrl->layout->eccpos;
>   	uint8_t *ecc_calc = chip->buffers->ecccalc;
>   	unsigned int max_bitflips = 0;
>   
> @@ -1279,17 +1286,17 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
>   	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
>   	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
>   
> -	for (i = 0; i < chip->ecc.total; i++)
> +	for (i = 0; i < mtd->eccctrl->total; i++)
>   		ecc_code[i] = chip->oob_poi[eccpos[i]];
>   
>   	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
>   		int stat;
>   
> -		chip->ecc.hwctl(mtd, NAND_ECC_READ);
> +		mtd->eccctrl->hwctl(mtd, NAND_ECC_READ);
>   		chip->read_buf(mtd, p, eccsize);
> -		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
> +		mtd->eccctrl->calculate(mtd, p, &ecc_calc[i]);
>   
> -		stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
> +		stat = mtd->eccctrl->correct(mtd, p, &ecc_code[i], NULL);
>   		if (stat < 0) {
>   			mtd->ecc_stats.failed++;
>   		} else {
> @@ -1314,9 +1321,9 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
>   static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
>   				   uint8_t *buf, int oob_required, int page)
>   {
> -	int i, eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> -	int eccsteps = chip->ecc.steps;
> +	int i, eccsize = mtd->eccctrl->size;
> +	int eccbytes = mtd->eccctrl->bytes;
> +	int eccsteps = mtd->eccctrl->steps;
>   	uint8_t *p = buf;
>   	uint8_t *oob = chip->oob_poi;
>   	unsigned int max_bitflips = 0;
> @@ -1324,17 +1331,17 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
>   	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
>   		int stat;
>   
> -		chip->ecc.hwctl(mtd, NAND_ECC_READ);
> +		mtd->eccctrl->hwctl(mtd, NAND_ECC_READ);
>   		chip->read_buf(mtd, p, eccsize);
>   
> -		if (chip->ecc.prepad) {
> -			chip->read_buf(mtd, oob, chip->ecc.prepad);
> -			oob += chip->ecc.prepad;
> +		if (mtd->eccctrl->prepad) {
> +			chip->read_buf(mtd, oob, mtd->eccctrl->prepad);
> +			oob += mtd->eccctrl->prepad;
>   		}
>   
> -		chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
> +		mtd->eccctrl->hwctl(mtd, NAND_ECC_READSYN);
>   		chip->read_buf(mtd, oob, eccbytes);
> -		stat = chip->ecc.correct(mtd, p, oob, NULL);
> +		stat = mtd->eccctrl->correct(mtd, p, oob, NULL);
>   
>   		if (stat < 0) {
>   			mtd->ecc_stats.failed++;
> @@ -1345,9 +1352,9 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
>   
>   		oob += eccbytes;
>   
> -		if (chip->ecc.postpad) {
> -			chip->read_buf(mtd, oob, chip->ecc.postpad);
> -			oob += chip->ecc.postpad;
> +		if (mtd->eccctrl->postpad) {
> +			chip->read_buf(mtd, oob, mtd->eccctrl->postpad);
> +			oob += mtd->eccctrl->postpad;
>   		}
>   	}
>   
> @@ -1361,14 +1368,16 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
>   
>   /**
>    * nand_transfer_oob - [INTERN] Transfer oob to client buffer
> - * @chip: nand chip structure
> + * @mtd: mtd structure
>    * @oob: oob destination address
>    * @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:
> @@ -1377,7 +1386,7 @@ 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 = mtd->eccctrl->layout->oobfree;
>   		uint32_t boffs = 0, roffs = ops->ooboffs;
>   		size_t bytes = 0;
>   
> @@ -1459,16 +1468,20 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
>   			 * the read methods return max bitflips per ecc step.
>   			 */
>   			if (unlikely(ops->mode == MTD_OPS_RAW))
> -				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
> -							      oob_required,
> -							      page);
> +				ret = mtd->eccctrl->read_page_raw(mtd, chip,
> +								  bufpoi,
> +								  oob_required,
> +								  page);
>   			else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
>   				 !oob)
> -				ret = chip->ecc.read_subpage(mtd, chip,
> -							col, bytes, bufpoi);
> +				ret = mtd->eccctrl->read_subpage(mtd, chip,
> +								 col, bytes,
> +								 bufpoi);
>   			else
> -				ret = chip->ecc.read_page(mtd, chip, bufpoi,
> -							  oob_required, page);
> +				ret = mtd->eccctrl->read_page(mtd, chip,
> +							      bufpoi,
> +							      oob_required,
> +							      page);
>   			if (ret < 0) {
>   				if (!aligned)
>   					/* Invalidate page cache */
> @@ -1498,8 +1511,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
>   				int toread = min(oobreadlen, max_oobsize);
>   
>   				if (toread) {
> -					oob = nand_transfer_oob(chip,
> -						oob, ops, toread);
> +					oob = nand_transfer_oob(mtd, oob, ops,
> +								toread);
>   					oobreadlen -= toread;
>   				}
>   			}
> @@ -1604,13 +1617,14 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
>   {
>   	uint8_t *buf = chip->oob_poi;
>   	int length = mtd->oobsize;
> -	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
> -	int eccsize = chip->ecc.size;
> +	int chunk = mtd->eccctrl->bytes + mtd->eccctrl->prepad +
> +		    mtd->eccctrl->postpad;
> +	int eccsize = mtd->eccctrl->size;
>   	uint8_t *bufpoi = buf;
>   	int i, toread, sndrnd = 0, pos;
>   
> -	chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
> -	for (i = 0; i < chip->ecc.steps; i++) {
> +	chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->eccctrl->size, page);
> +	for (i = 0; i < mtd->eccctrl->steps; i++) {
>   		if (sndrnd) {
>   			pos = eccsize + i * (eccsize + chunk);
>   			if (mtd->writesize > 512)
> @@ -1663,9 +1677,10 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
>   static int nand_write_oob_syndrome(struct mtd_info *mtd,
>   				   struct nand_chip *chip, int page)
>   {
> -	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
> -	int eccsize = chip->ecc.size, length = mtd->oobsize;
> -	int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
> +	int chunk = mtd->eccctrl->bytes + mtd->eccctrl->prepad +
> +		    mtd->eccctrl->postpad;
> +	int eccsize = mtd->eccctrl->size, length = mtd->oobsize;
> +	int i, len, pos, status = 0, sndcmd = 0, steps = mtd->eccctrl->steps;
>   	const uint8_t *bufpoi = chip->oob_poi;
>   
>   	/*
> @@ -1673,7 +1688,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
>   	 * or
>   	 * data-pad-ecc-pad-data-pad .... ecc-pad-oob
>   	 */
> -	if (!chip->ecc.prepad && !chip->ecc.postpad) {
> +	if (!mtd->eccctrl->prepad && !mtd->eccctrl->postpad) {
>   		pos = steps * (eccsize + chunk);
>   		steps = 0;
>   	} else
> @@ -1737,7 +1752,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->eccctrl->layout->oobavail;
>   	else
>   		len = mtd->oobsize;
>   
> @@ -1765,15 +1780,15 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
>   
>   	while (1) {
>   		if (ops->mode == MTD_OPS_RAW)
> -			ret = chip->ecc.read_oob_raw(mtd, chip, page);
> +			ret = mtd->eccctrl->read_oob_raw(mtd, chip, page);
>   		else
> -			ret = chip->ecc.read_oob(mtd, chip, page);
> +			ret = mtd->eccctrl->read_oob(mtd, chip, page);
>   
>   		if (ret < 0)
>   			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 */
> @@ -1888,26 +1903,26 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
>   					struct nand_chip *chip,
>   					const uint8_t *buf, int oob_required)
>   {
> -	int eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> +	int eccsize = mtd->eccctrl->size;
> +	int eccbytes = mtd->eccctrl->bytes;
>   	uint8_t *oob = chip->oob_poi;
>   	int steps, size;
>   
> -	for (steps = chip->ecc.steps; steps > 0; steps--) {
> +	for (steps = mtd->eccctrl->steps; steps > 0; steps--) {
>   		chip->write_buf(mtd, buf, eccsize);
>   		buf += eccsize;
>   
> -		if (chip->ecc.prepad) {
> -			chip->write_buf(mtd, oob, chip->ecc.prepad);
> -			oob += chip->ecc.prepad;
> +		if (mtd->eccctrl->prepad) {
> +			chip->write_buf(mtd, oob, mtd->eccctrl->prepad);
> +			oob += mtd->eccctrl->prepad;
>   		}
>   
>   		chip->write_buf(mtd, oob, eccbytes);
>   		oob += eccbytes;
>   
> -		if (chip->ecc.postpad) {
> -			chip->write_buf(mtd, oob, chip->ecc.postpad);
> -			oob += chip->ecc.postpad;
> +		if (mtd->eccctrl->postpad) {
> +			chip->write_buf(mtd, oob, mtd->eccctrl->postpad);
> +			oob += mtd->eccctrl->postpad;
>   		}
>   	}
>   
> @@ -1927,21 +1942,21 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
>   static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
>   				  const uint8_t *buf, int oob_required)
>   {
> -	int i, eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> -	int eccsteps = chip->ecc.steps;
> +	int i, eccsize = mtd->eccctrl->size;
> +	int eccbytes = mtd->eccctrl->bytes;
> +	int eccsteps = mtd->eccctrl->steps;
>   	uint8_t *ecc_calc = chip->buffers->ecccalc;
>   	const uint8_t *p = buf;
> -	uint32_t *eccpos = chip->ecc.layout->eccpos;
> +	uint32_t *eccpos = mtd->eccctrl->layout->eccpos;
>   
>   	/* Software ECC calculation */
>   	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
> -		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
> +		mtd->eccctrl->calculate(mtd, p, &ecc_calc[i]);
>   
> -	for (i = 0; i < chip->ecc.total; i++)
> +	for (i = 0; i < mtd->eccctrl->total; i++)
>   		chip->oob_poi[eccpos[i]] = ecc_calc[i];
>   
> -	return chip->ecc.write_page_raw(mtd, chip, buf, 1);
> +	return mtd->eccctrl->write_page_raw(mtd, chip, buf, 1);
>   }
>   
>   /**
> @@ -1954,20 +1969,20 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
>   static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
>   				  const uint8_t *buf, int oob_required)
>   {
> -	int i, eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> -	int eccsteps = chip->ecc.steps;
> +	int i, eccsize = mtd->eccctrl->size;
> +	int eccbytes = mtd->eccctrl->bytes;
> +	int eccsteps = mtd->eccctrl->steps;
>   	uint8_t *ecc_calc = chip->buffers->ecccalc;
>   	const uint8_t *p = buf;
> -	uint32_t *eccpos = chip->ecc.layout->eccpos;
> +	uint32_t *eccpos = mtd->eccctrl->layout->eccpos;
>   
>   	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
> -		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
> +		mtd->eccctrl->hwctl(mtd, NAND_ECC_WRITE);
>   		chip->write_buf(mtd, p, eccsize);
> -		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
> +		mtd->eccctrl->calculate(mtd, p, &ecc_calc[i]);
>   	}
>   
> -	for (i = 0; i < chip->ecc.total; i++)
> +	for (i = 0; i < mtd->eccctrl->total; i++)
>   		chip->oob_poi[eccpos[i]] = ecc_calc[i];
>   
>   	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
> @@ -1992,10 +2007,10 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
>   {
>   	uint8_t *oob_buf  = chip->oob_poi;
>   	uint8_t *ecc_calc = chip->buffers->ecccalc;
> -	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;
> +	int ecc_size      = mtd->eccctrl->size;
> +	int ecc_bytes     = mtd->eccctrl->bytes;
> +	int ecc_steps     = mtd->eccctrl->steps;
> +	uint32_t *eccpos  = mtd->eccctrl->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;
> @@ -2003,7 +2018,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
>   
>   	for (step = 0; step < ecc_steps; step++) {
>   		/* configure controller for WRITE access */
> -		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
> +		mtd->eccctrl->hwctl(mtd, NAND_ECC_WRITE);
>   
>   		/* write data (untouched subpages already masked by 0xFF) */
>   		chip->write_buf(mtd, buf, ecc_size);
> @@ -2012,7 +2027,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
>   		if ((step < start_step) || (step > end_step))
>   			memset(ecc_calc, 0xff, ecc_bytes);
>   		else
> -			chip->ecc.calculate(mtd, buf, ecc_calc);
> +			mtd->eccctrl->calculate(mtd, buf, ecc_calc);
>   
>   		/* mask OOB of un-touched subpages by padding 0xFF */
>   		/* if oob_required, preserve OOB metadata of written subpage */
> @@ -2027,7 +2042,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
>   	/* copy calculated ECC for whole page to chip->buffer->oob */
>   	/* this include masked-value(0xFF) for unwritten subpages */
>   	ecc_calc = chip->buffers->ecccalc;
> -	for (i = 0; i < chip->ecc.total; i++)
> +	for (i = 0; i < mtd->eccctrl->total; i++)
>   		chip->oob_poi[eccpos[i]] = ecc_calc[i];
>   
>   	/* write OOB buffer to NAND device */
> @@ -2051,29 +2066,29 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
>   				    struct nand_chip *chip,
>   				    const uint8_t *buf, int oob_required)
>   {
> -	int i, eccsize = chip->ecc.size;
> -	int eccbytes = chip->ecc.bytes;
> -	int eccsteps = chip->ecc.steps;
> +	int i, eccsize = mtd->eccctrl->size;
> +	int eccbytes = mtd->eccctrl->bytes;
> +	int eccsteps = mtd->eccctrl->steps;
>   	const uint8_t *p = buf;
>   	uint8_t *oob = chip->oob_poi;
>   
>   	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
>   
> -		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
> +		mtd->eccctrl->hwctl(mtd, NAND_ECC_WRITE);
>   		chip->write_buf(mtd, p, eccsize);
>   
> -		if (chip->ecc.prepad) {
> -			chip->write_buf(mtd, oob, chip->ecc.prepad);
> -			oob += chip->ecc.prepad;
> +		if (mtd->eccctrl->prepad) {
> +			chip->write_buf(mtd, oob, mtd->eccctrl->prepad);
> +			oob += mtd->eccctrl->prepad;
>   		}
>   
> -		chip->ecc.calculate(mtd, p, oob);
> +		mtd->eccctrl->calculate(mtd, p, oob);
>   		chip->write_buf(mtd, oob, eccbytes);
>   		oob += eccbytes;
>   
> -		if (chip->ecc.postpad) {
> -			chip->write_buf(mtd, oob, chip->ecc.postpad);
> -			oob += chip->ecc.postpad;
> +		if (mtd->eccctrl->postpad) {
> +			chip->write_buf(mtd, oob, mtd->eccctrl->postpad);
> +			oob += mtd->eccctrl->postpad;
>   		}
>   	}
>   
> @@ -2104,7 +2119,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
>   	int status, subpage;
>   
>   	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
> -		chip->ecc.write_subpage)
> +		mtd->eccctrl->write_subpage)
>   		subpage = offset || (data_len < mtd->writesize);
>   	else
>   		subpage = 0;
> @@ -2112,13 +2127,15 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
>   	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
>   
>   	if (unlikely(raw))
> -		status = chip->ecc.write_page_raw(mtd, chip, buf,
> -							oob_required);
> +		status = mtd->eccctrl->write_page_raw(mtd, chip, buf,
> +						      oob_required);
>   	else if (subpage)
> -		status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
> -							 buf, oob_required);
> +		status = mtd->eccctrl->write_subpage(mtd, chip, offset,
> +						     data_len, buf,
> +						     oob_required);
>   	else
> -		status = chip->ecc.write_page(mtd, chip, buf, oob_required);
> +		status = mtd->eccctrl->write_page(mtd, chip, buf,
> +						  oob_required);
>   
>   	if (status < 0)
>   		return status;
> @@ -2177,7 +2194,7 @@ 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 = mtd->eccctrl->layout->oobfree;
>   		uint32_t boffs = 0, woffs = ops->ooboffs;
>   		size_t bytes = 0;
>   
> @@ -2405,7 +2422,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->eccctrl->layout->oobavail;
>   	else
>   		len = mtd->oobsize;
>   
> @@ -2459,9 +2476,11 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
>   	nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
>   
>   	if (ops->mode == MTD_OPS_RAW)
> -		status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
> +		status = mtd->eccctrl->write_oob_raw(mtd, chip,
> +						     page & chip->pagemask);
>   	else
> -		status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
> +		status = mtd->eccctrl->write_oob(mtd, chip,
> +						 page & chip->pagemask);
>   
>   	chip->select_chip(mtd, -1);
>   
> @@ -3582,32 +3601,9 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
>   }
>   EXPORT_SYMBOL(nand_scan_ident);
>   
> -
> -/**
> - * nand_scan_tail - [NAND Interface] Scan for the NAND device
> - * @mtd: MTD device structure
> - *
> - * This is the second phase of the normal nand_scan() function. It fills out
> - * all the uninitialized function pointers with the defaults and scans for a
> - * bad block table if appropriate.
> - */
> -int nand_scan_tail(struct mtd_info *mtd)
> +int nand_ecc_ctrl_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc)
>   {
>   	int i;
> -	struct nand_chip *chip = mtd->priv;
> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
> -
> -	/* New bad blocks should be marked in OOB, flash-based BBT, or both */
> -	BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
> -			!(chip->bbt_options & NAND_BBT_USE_FLASH));
> -
> -	if (!(chip->options & NAND_OWN_BUFFERS))
> -		chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
> -	if (!chip->buffers)
> -		return -ENOMEM;
> -
> -	/* Set the internal oob buffer location, just after the page data */
> -	chip->oob_poi = chip->buffers->databuf + mtd->writesize;
>   
>   	/*
>   	 * If no default placement scheme is given, select an appropriate one.
> @@ -3633,14 +3629,10 @@ int nand_scan_tail(struct mtd_info *mtd)
>   		}
>   	}
>   
> -	if (!chip->write_page)
> -		chip->write_page = nand_write_page;
> -
>   	/*
>   	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is
>   	 * selected and we have 256 byte pagesize fallback to software ECC
>   	 */
> -
>   	switch (ecc->mode) {
>   	case NAND_ECC_HW_OOB_FIRST:
>   		/* Similar to NAND_ECC_HW, but a separate read_page handle */
> @@ -3789,7 +3781,6 @@ int nand_scan_tail(struct mtd_info *mtd)
>   	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;
>   
>   	/*
>   	 * Set the number of read / write steps for one page depending on ECC
> @@ -3802,6 +3793,111 @@ int nand_scan_tail(struct mtd_info *mtd)
>   	}
>   	ecc->total = ecc->steps * ecc->bytes;
>   
> +	return 0;
> +}
> +EXPORT_SYMBOL(nand_ecc_ctrl_init);
> +
> +
> +static void nand_release_ecc_ctrl(const struct nand_ecc_ctrl *ecc)
> +{
> +	if (ecc->mode == NAND_ECC_SOFT_BCH)
> +		nand_bch_free((struct nand_bch_control *)ecc->priv);
> +
> +	kfree(ecc);
> +}
> +
> +const struct nand_ecc_ctrl *nand_get_ecc_ctrl(struct mtd_info *mtd,
> +					      nand_ecc_modes_t mode,
> +					      struct device_node *np)
> +{
> +	struct nand_chip *chip = mtd->priv;
> +	struct nand_ecc_ctrl *ecc;
> +	u32 ecc_step, ecc_strength;
> +	int ret;
> +
> +	if (mode != NAND_ECC_NONE && mode != NAND_ECC_SOFT &&
> +	    mode != NAND_ECC_SOFT_BCH)
> +		return ERR_PTR(-EINVAL);
> +
> +	ecc = kzalloc(sizeof(*ecc), GFP_KERNEL);
> +	if (!ecc)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ecc->size = chip->ecc_step_ds;
> +	ecc->strength = chip->ecc_strength_ds;
> +	if (!of_get_nand_ecc_level(np, &ecc_strength, &ecc_step)) {
> +		ecc->size = ecc_step;
> +		ecc->strength = ecc_strength;
> +	}
> +
> +	switch (mode) {
> +	case NAND_ECC_NONE:
> +		break;
> +	case NAND_ECC_SOFT:
> +		break;
> +	case NAND_ECC_SOFT_BCH:
> +		ecc->bytes = ((ecc->strength * fls(8 * ecc->size)) + 7) / 8;
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	ecc->mode = mode;
> +	ret = nand_ecc_ctrl_init(mtd, ecc);
> +	if (ret)
> +		goto err;
> +
> +	ecc->release = nand_release_ecc_ctrl;
> +
> +	return ecc;
> +
> +err:
> +	kfree(ecc);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL(nand_get_ecc_ctrl);
> +
> +/**
> + * nand_scan_tail - [NAND Interface] Scan for the NAND device
> + * @mtd: MTD device structure
> + *
> + * This is the second phase of the normal nand_scan() function. It fills out
> + * all the uninitialized function pointers with the defaults and scans for a
> + * bad block table if appropriate.
> + */
> +int nand_scan_tail(struct mtd_info *mtd)
> +{
> +	struct nand_chip *chip = mtd->priv;
> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
> +	int ret;
> +	/*struct nand_rnd_ctrl *rnd = &chip->rnd;*/
> +
> +	/* New bad blocks should be marked in OOB, flash-based BBT, or both */
> +	BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
> +			!(chip->bbt_options & NAND_BBT_USE_FLASH));
> +
> +	if (!(chip->options & NAND_OWN_BUFFERS))
> +		chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
> +	if (!chip->buffers)
> +		return -ENOMEM;
> +
> +	/* Set the internal oob buffer location, just after the page data */
> +	chip->oob_poi = chip->buffers->databuf + mtd->writesize;
> +
> +	if (!chip->write_page)
> +		chip->write_page = nand_write_page;
> +
> +	if (!chip->get_ecc_ctrl)
> +		chip->get_ecc_ctrl = nand_get_ecc_ctrl;
> +
> +	ret = nand_ecc_ctrl_init(mtd, ecc);
> +	if (ret)
> +		return ret;
> +
> +	mtd->eccctrl = &chip->ecc;
> +	mtd->oobavail = ecc->layout->oobavail;
> +
>   	/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
>   	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
>   		switch (ecc->steps) {
> diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
> index d64f8c3..0365c1e 100644
> --- a/drivers/mtd/ofpart.c
> +++ b/drivers/mtd/ofpart.c
> @@ -16,6 +16,7 @@
>   #include <linux/module.h>
>   #include <linux/init.h>
>   #include <linux/of.h>
> +#include <linux/of_mtd.h>
>   #include <linux/mtd/mtd.h>
>   #include <linux/slab.h>
>   #include <linux/mtd/partitions.h>
> @@ -25,6 +26,25 @@ static bool node_has_compatible(struct device_node *pp)
>   	return of_get_property(pp, "compatible", NULL);
>   }
>   
> +static int parse_ofnandpart(struct mtd_info *master,
> +			    struct mtd_partition *part,
> +			    struct device_node *pp)
> +{
> +	struct nand_chip *chip = master->priv;
> +	int mode = of_get_nand_ecc_mode(pp);
> +	const struct nand_ecc_ctrl *ret;
> +
> +	if (mode < 0)
> +		return 0;
> +
> +	ret = chip->get_ecc_ctrl(master, mode, pp);
> +	if (IS_ERR(ret))
> +		return PTR_ERR(ret);
> +
> +	part->eccctrl = ret;
> +	return 0;
> +}
> +
>   static int parse_ofpart_partitions(struct mtd_info *master,
>   				   struct mtd_partition **pparts,
>   				   struct mtd_part_parser_data *data)
> @@ -63,6 +83,7 @@ static int parse_ofpart_partitions(struct mtd_info *master,
>   		const __be32 *reg;
>   		int len;
>   		int a_cells, s_cells;
> +		int ret;
>   
>   		if (node_has_compatible(pp))
>   			continue;
> @@ -89,6 +110,20 @@ static int parse_ofpart_partitions(struct mtd_info *master,
>   		if (of_get_property(pp, "lock", &len))
>   			(*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
>   
> +		switch (master->type) {
> +		case MTD_NANDFLASH:
> +		case MTD_MLCNANDFLASH:
> +			ret = parse_ofnandpart(master, &(*pparts)[i], pp);
> +			if (ret) {
> +				nr_parts--;
> +				continue;
> +			}
> +
> +			break;
> +		default:
> +			break;
> +		}
> +
>   		i++;
>   	}
>   
> diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> index 8cc0e2f..7b08d50 100644
> --- a/include/linux/mtd/mtd.h
> +++ b/include/linux/mtd/mtd.h
> @@ -109,6 +109,8 @@ struct nand_ecclayout {
>   	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
>   };
>   
> +struct nand_ecc_ctrl;
> +
>   struct module;	/* only needed for owner field in mtd_info */
>   
>   struct mtd_info {
> @@ -169,6 +171,7 @@ struct mtd_info {
>   
>   	/* ECC layout structure pointer - read only! */
>   	struct nand_ecclayout *ecclayout;
> +	const struct nand_ecc_ctrl *eccctrl;
>   
>   	/* the ecc step size. */
>   	unsigned int ecc_step_size;
> diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
> index c70e0a3..d3f0cfd 100644
> --- a/include/linux/mtd/nand.h
> +++ b/include/linux/mtd/nand.h
> @@ -407,8 +407,11 @@ struct nand_ecc_ctrl {
>   	int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page);
>   	int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
>   			int page);
> +	void (*release)(const struct nand_ecc_ctrl *ctrl);
>   };
>   
> +
> +
>   /**
>    * struct nand_buffers - buffer structure for read/write
>    * @ecccalc:	buffer for calculated ECC
> @@ -544,6 +547,9 @@ struct nand_chip {
>   			int feature_addr, uint8_t *subfeature_para);
>   	int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
>   			int feature_addr, uint8_t *subfeature_para);
> +	const struct nand_ecc_ctrl *(*get_ecc_ctrl)(struct mtd_info *mtd,
> +						    nand_ecc_modes_t mode,
> +						    struct device_node *np);
>   
>   	int chip_delay;
>   	unsigned int options;
> @@ -699,6 +705,12 @@ extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
>   extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
>   			size_t *retlen, uint8_t *buf);
>   
> +int nand_ecc_ctrl_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc);
> +
> +const struct nand_ecc_ctrl *nand_get_ecc_ctrl(struct mtd_info *mtd,
> +					      nand_ecc_modes_t mode,
> +					      struct device_node *np);
> +
>   /**
>    * struct platform_nand_chip - chip level device structure
>    * @nr_chips:		max. number of chips to scan for
> diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
> index 1f8d24b..9e39fb1 100644
> --- a/include/linux/mtd/partitions.h
> +++ b/include/linux/mtd/partitions.h
> @@ -42,6 +42,7 @@ struct mtd_partition {
>   	uint64_t offset;		/* offset within the master MTD space */
>   	uint32_t mask_flags;		/* master MTD flags to mask out for this partition */
>   	struct nand_ecclayout *ecclayout;	/* out of band layout for this partition (NAND only) */
> +	const struct nand_ecc_ctrl *eccctrl;	/* NAND ECC config for this partition (NAND only) */
>   };
>   
>   #define MTDPART_OFS_RETAIN	(-3)




More information about the linux-mtd mailing list