[U-Boot] [PATCH 7/7] mtd: nand: Sync with Linux v4.6

Boris Brezillon boris.brezillon at free-electrons.com
Tue May 31 09:10:55 CEST 2016


Hi Scott,

On Mon, 30 May 2016 13:57:58 -0500
Scott Wood <oss at buserror.net> wrote:

> Updates the NAND code to match Linux v4.6.  The previous sync was from
> Linux v4.1 in commit d3963721d93fafa.
> 
> Note that none of the individual NAND drivers tracked Linux closely
> enough to be synced themselves, other than manually applying a few
> cross-tree changes.

Nice work!
I'll port my sunxi NAND controller driver on top of these changes and
test it.

Thanks a lot.

Boris

> 
> Signed-off-by: Scott Wood <oss at buserror.net>
> ---
>  drivers/mtd/nand/atmel_nand.c   |   6 +-
>  drivers/mtd/nand/davinci_nand.c |   6 +-
>  drivers/mtd/nand/denali.c       |  39 +++--
>  drivers/mtd/nand/denali.h       |   1 -
>  drivers/mtd/nand/denali_spl.c   |   2 +-
>  drivers/mtd/nand/mpc5121_nfc.c  |   1 -
>  drivers/mtd/nand/mxc_nand.c     |   5 +-
>  drivers/mtd/nand/mxc_nand_spl.c |   2 +-
>  drivers/mtd/nand/mxs_nand.c     |   2 +-
>  drivers/mtd/nand/nand_base.c    | 329 ++++++++++++++++++++++++++++------------
>  drivers/mtd/nand/nand_bbt.c     |  30 ++--
>  drivers/mtd/nand/nand_bch.c     |  29 ++--
>  drivers/mtd/nand/nand_ids.c     |  10 +-
>  drivers/mtd/nand/ndfc.c         |   2 +-
>  drivers/mtd/nand/omap_gpmc.c    |   2 +-
>  drivers/mtd/nand/s3c2410_nand.c |   2 +-
>  drivers/mtd/nand/vf610_nfc.c    |   1 -
>  include/linux/mtd/mtd.h         |   5 +
>  include/linux/mtd/nand.h        |  65 +++++---
>  include/linux/mtd/nand_bch.h    |  10 +-
>  20 files changed, 347 insertions(+), 202 deletions(-)
> 
> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
> index a81b96d..75e8307 100644
> --- a/drivers/mtd/nand/atmel_nand.c
> +++ b/drivers/mtd/nand/atmel_nand.c
> @@ -513,7 +513,7 @@ normal_check:
>  			if (err_nbr == -1) {
>  				dev_err(host->dev, "PMECC: Too many errors\n");
>  				mtd->ecc_stats.failed++;
> -				return -EIO;
> +				return -EBADMSG;
>  			} else {
>  				pmecc_correct_data(mtd, buf_pos, ecc, i,
>  					host->pmecc_bytes_per_sector, err_nbr);
> @@ -562,7 +562,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
>  	stat = pmecc_readl(host->pmecc, isr);
>  	if (stat != 0)
>  		if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
> -			return -EIO;
> +			return -EBADMSG;
>  
>  	return 0;
>  }
> @@ -1112,7 +1112,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
>  		 * We can't correct so many errors */
>  		dev_warn(host->dev, "atmel_nand : multiple errors detected."
>  				" Unable to correct.\n");
> -		return -EIO;
> +		return -EBADMSG;
>  	}
>  
>  	/* if there's a single bit error : we can correct it */
> diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
> index be9d666..48a8ca7 100644
> --- a/drivers/mtd/nand/davinci_nand.c
> +++ b/drivers/mtd/nand/davinci_nand.c
> @@ -243,7 +243,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat,
>  					 "%d\n", find_byte, find_bit);
>  				return 1;
>  			} else {
> -				return -1;
> +				return -EBADMSG;
>  			}
>  		} else if (!(diff & (diff - 1))) {
>  			/* Single bit ECC error in the ECC itself,
> @@ -254,7 +254,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat,
>  		} else {
>  			/* Uncorrectable error */
>  			MTDDEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
> -			return -1;
> +			return -EBADMSG;
>  		}
>  	}
>  	return 0;
> @@ -701,7 +701,7 @@ static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat,
>  		return 0;
>  	} else if (iserror == ECC_STATE_TOO_MANY_ERRS) {
>  		val = __raw_readl(&davinci_emif_regs->nanderrval1);
> -		return -1;
> +		return -EBADMSG;
>  	}
>  
>  	numerrors = ((__raw_readl(&davinci_emif_regs->nandfsr) >> 16)
> diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
> index 3ae7545..601e744 100644
> --- a/drivers/mtd/nand/denali.c
> +++ b/drivers/mtd/nand/denali.c
> @@ -48,8 +48,10 @@ static int onfi_timing_mode = NAND_DEFAULT_TIMINGS;
>   * this macro allows us to convert from an MTD structure to our own
>   * device context (denali) structure.
>   */
> -#define mtd_to_denali(m) \
> -	container_of(mtd_to_nand(m), struct denali_nand_info, nand)
> +static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
> +{
> +	return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
> +}
>  
>  /*
>   * These constants are defined by the driver to enable common driver
> @@ -866,8 +868,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
>   * by write_page above.
>   */
>  static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
> -				const uint8_t *buf, int oob_required,
> -				int page)
> +				const uint8_t *buf, int oob_required, int page)
>  {
>  	struct denali_nand_info *denali = mtd_to_denali(mtd);
>  
> @@ -891,8 +892,8 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
>   * write_page() function above.
>   */
>  static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
> -					const uint8_t *buf, int oob_required,
> -					int page)
> +				 const uint8_t *buf, int oob_required,
> +				 int page)
>  {
>  	struct denali_nand_info *denali = mtd_to_denali(mtd);
>  
> @@ -991,7 +992,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
>  			debug("  ECC error cause by erased block\n");
>  			/* false alarm, return the 0xFF */
>  		} else {
> -			return -EIO;
> +			return -EBADMSG;
>  		}
>  	}
>  	memcpy(buf, denali->buf.dma_buf, mtd->writesize);
> @@ -1176,12 +1177,13 @@ static struct nand_ecclayout nand_oob;
>  
>  static int denali_init(struct denali_nand_info *denali)
>  {
> +	struct mtd_info *mtd = nand_to_mtd(&denali->nand);
>  	int ret;
>  
>  	denali_hw_init(denali);
>  
> -	denali->mtd->name = "denali-nand";
> -	denali->mtd->owner = THIS_MODULE;
> +	mtd->name = "denali-nand";
> +	mtd->owner = THIS_MODULE;
>  
>  	/* register the driver with the NAND core subsystem */
>  	denali->nand.select_chip = denali_select_chip;
> @@ -1195,7 +1197,7 @@ static int denali_init(struct denali_nand_info *denali)
>  	 * this is the first stage in a two step process to register
>  	 * with the nand subsystem
>  	 */
> -	if (nand_scan_ident(denali->mtd, denali->max_banks, NULL)) {
> +	if (nand_scan_ident(mtd, denali->max_banks, NULL)) {
>  		ret = -ENXIO;
>  		goto fail;
>  	}
> @@ -1241,13 +1243,13 @@ static int denali_init(struct denali_nand_info *denali)
>  	nand_oob.eccbytes = denali->nand.ecc.bytes;
>  	denali->nand.ecc.layout = &nand_oob;
>  
> -	writel(denali->mtd->erasesize / denali->mtd->writesize,
> +	writel(mtd->erasesize / mtd->writesize,
>  	       denali->flash_reg + PAGES_PER_BLOCK);
>  	writel(denali->nand.options & NAND_BUSWIDTH_16 ? 1 : 0,
>  	       denali->flash_reg + DEVICE_WIDTH);
> -	writel(denali->mtd->writesize,
> +	writel(mtd->writesize,
>  	       denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
> -	writel(denali->mtd->oobsize,
> +	writel(mtd->oobsize,
>  	       denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
>  	if (readl(denali->flash_reg + DEVICES_CONNECTED) == 0)
>  		writel(1, denali->flash_reg + DEVICES_CONNECTED);
> @@ -1260,12 +1262,12 @@ static int denali_init(struct denali_nand_info *denali)
>  	denali->nand.ecc.read_oob = denali_read_oob;
>  	denali->nand.ecc.write_oob = denali_write_oob;
>  
> -	if (nand_scan_tail(denali->mtd)) {
> +	if (nand_scan_tail(mtd)) {
>  		ret = -ENXIO;
>  		goto fail;
>  	}
>  
> -	ret = nand_register(0, denali->mtd);
> +	ret = nand_register(0, mtd);
>  
>  fail:
>  	return ret;
> @@ -1280,13 +1282,6 @@ static int __board_nand_init(void)
>  		return -ENOMEM;
>  
>  	/*
> -	 * If CONFIG_SYS_NAND_SELF_INIT is defined, each driver is responsible
> -	 * for instantiating struct nand_chip, while drivers/mtd/nand/nand.c
> -	 * still provides a "struct mtd_info nand_info" instance.
> -	 */
> -	denali->mtd = &denali->nand.mtd;
> -
> -	/*
>  	 * In the future, these base addresses should be taken from
>  	 * Device Tree or platform data.
>  	 */
> diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
> index db1457a..0e098bd 100644
> --- a/drivers/mtd/nand/denali.h
> +++ b/drivers/mtd/nand/denali.h
> @@ -436,7 +436,6 @@ struct nand_buf {
>  #define DT		3
>  
>  struct denali_nand_info {
> -	struct mtd_info *mtd;
>  	struct nand_chip nand;
>  	int flash_bank; /* currently selected chip */
>  	int status;
> diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/denali_spl.c
> index 1587413..c693032 100644
> --- a/drivers/mtd/nand/denali_spl.c
> +++ b/drivers/mtd/nand/denali_spl.c
> @@ -41,7 +41,7 @@ static int wait_for_irq(uint32_t irq_mask)
>  
>  		if (intr_status & INTR_STATUS__ECC_UNCOR_ERR) {
>  			debug("Uncorrected ECC detected\n");
> -			return -EIO;
> +			return -EBADMSG;
>  		}
>  
>  		if (intr_status & irq_mask)
> diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
> index 362d393..8a8775c 100644
> --- a/drivers/mtd/nand/mpc5121_nfc.c
> +++ b/drivers/mtd/nand/mpc5121_nfc.c
> @@ -100,7 +100,6 @@
>  #define NFC_WPC_UNLOCK		(1 << 2)
>  
>  struct mpc5121_nfc_prv {
> -	struct mtd_info mtd;
>  	struct nand_chip chip;
>  	int irq;
>  	void __iomem *regs;
> diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
> index d4e14b5..7221d0b 100644
> --- a/drivers/mtd/nand/mxc_nand.c
> +++ b/drivers/mtd/nand/mxc_nand.c
> @@ -19,7 +19,6 @@
>  #define DRIVER_NAME "mxc_nand"
>  
>  struct mxc_nand_host {
> -	struct mtd_info			mtd;
>  	struct nand_chip		*nand;
>  
>  	struct mxc_nand_regs __iomem	*regs;
> @@ -681,7 +680,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
>  				       mtd->writesize / nand_chip->subpagesize
>  					    - subpages);
>  			}
> -			return -1;
> +			return -EBADMSG;
>  		}
>  		ecc_status >>= 4;
>  		subpages--;
> @@ -713,7 +712,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
>  	if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
>  		MTDDEBUG(MTD_DEBUG_LEVEL0,
>  		      "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
> -		return -1;
> +		return -EBADMSG;
>  	}
>  
>  	return 0;
> diff --git a/drivers/mtd/nand/mxc_nand_spl.c b/drivers/mtd/nand/mxc_nand_spl.c
> index 6ac2c96..841fb5b 100644
> --- a/drivers/mtd/nand/mxc_nand_spl.c
> +++ b/drivers/mtd/nand/mxc_nand_spl.c
> @@ -232,7 +232,7 @@ static int nfc_read_page(unsigned int page_address, unsigned char *buf)
>  	nfc_nand_read_page(page_address);
>  
>  	if (nfc_nand_check_ecc())
> -		return -1;
> +		return -EBADMSG;
>  
>  	src = (u32 *)&nfc->main_area[0][0];
>  	dst = (u32 *)buf;
> diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c
> index 5291330..7be1f86 100644
> --- a/drivers/mtd/nand/mxs_nand.c
> +++ b/drivers/mtd/nand/mxs_nand.c
> @@ -961,7 +961,7 @@ static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
>   * Thus, this function is only called when we want *all* blocks to look good,
>   * so it *always* return success.
>   */
> -static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
> +static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
>  {
>  	return 0;
>  }
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index 62e70a7..74c563c 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -1,6 +1,4 @@
>  /*
> - *  drivers/mtd/nand.c
> - *
>   *  Overview:
>   *   This is the generic MTD driver for NAND flash devices. It should be
>   *   capable of working with almost all NAND chips currently available.
> @@ -45,8 +43,6 @@
>  #include <asm/io.h>
>  #include <asm/errno.h>
>  
> -static bool is_module_text_address(unsigned long addr) {return 0;}
> -
>  /* Define default oob placement schemes for large and small page devices */
>  static struct nand_ecclayout nand_oob_8 = {
>  	.eccbytes = 3,
> @@ -343,13 +339,12 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
>   * nand_block_bad - [DEFAULT] Read bad block marker from the chip
>   * @mtd: MTD device structure
>   * @ofs: offset from device start
> - * @getchip: 0, if the chip is already selected
>   *
>   * Check, if the block is bad.
>   */
> -static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
> +static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
>  {
> -	int page, chipnr, res = 0, i = 0;
> +	int page, res = 0, i = 0;
>  	struct nand_chip *chip = mtd_to_nand(mtd);
>  	u16 bad;
>  
> @@ -358,15 +353,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
>  
>  	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
>  
> -	if (getchip) {
> -		chipnr = (int)(ofs >> chip->chip_shift);
> -
> -		nand_get_device(mtd, FL_READING);
> -
> -		/* Select the NAND device */
> -		chip->select_chip(mtd, chipnr);
> -	}
> -
>  	do {
>  		if (chip->options & NAND_BUSWIDTH_16) {
>  			chip->cmdfunc(mtd, NAND_CMD_READOOB,
> @@ -391,11 +377,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
>  		i++;
>  	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
>  
> -	if (getchip) {
> -		chip->select_chip(mtd, -1);
> -		nand_release_device(mtd);
> -	}
> -
>  	return res;
>  }
>  
> @@ -533,14 +514,12 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
>   * nand_block_checkbad - [GENERIC] Check if a block is marked bad
>   * @mtd: MTD device structure
>   * @ofs: offset from device start
> - * @getchip: 0, if the chip is already selected
>   * @allowbbt: 1, if its allowed to access the bbt area
>   *
>   * Check, if the block is bad. Either by reading the bad block table or
>   * calling of the scan function.
>   */
> -static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
> -			       int allowbbt)
> +static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
>  {
>  	struct nand_chip *chip = mtd_to_nand(mtd);
>  
> @@ -551,17 +530,22 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
>  	}
>  
>  	if (!chip->bbt)
> -		return chip->block_bad(mtd, ofs, getchip);
> +		return chip->block_bad(mtd, ofs);
>  
>  	/* Return info from the table */
>  	return nand_isbad_bbt(mtd, ofs, allowbbt);
>  }
>  
> -/* Wait for the ready pin, after a command. The timeout is caught later. */
> +/**
> + * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
> + * @mtd: MTD device structure
> + *
> + * Wait for the ready pin after a command, and warn if a timeout occurs.
> + */
>  void nand_wait_ready(struct mtd_info *mtd)
>  {
>  	struct nand_chip *chip = mtd_to_nand(mtd);
> -	u32 timeo = (CONFIG_SYS_HZ * 20) / 1000;
> +	u32 timeo = (CONFIG_SYS_HZ * 400) / 1000;
>  	u32 time_start;
>  
>  	time_start = get_timer(0);
> @@ -571,6 +555,9 @@ void nand_wait_ready(struct mtd_info *mtd)
>  			if (chip->dev_ready(mtd))
>  				break;
>  	}
> +
> +	if (!chip->dev_ready(mtd))
> +		pr_warn("timeout while waiting for chip to become ready\n");
>  }
>  EXPORT_SYMBOL_GPL(nand_wait_ready);
>  
> @@ -871,15 +858,13 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
>   * @mtd: MTD device structure
>   * @chip: NAND chip structure
>   *
> - * Wait for command done. This applies to erase and program only. Erase can
> - * take up to 400ms and program up to 20ms according to general NAND and
> - * SmartMedia specs.
> + * Wait for command done. This applies to erase and program only.
>   */
>  static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
>  {
>  
> -	int status, state = chip->state;
> -	unsigned long timeo = (state == FL_ERASING ? 400 : 20);
> +	int status;
> +	unsigned long timeo = 400;
>  
>  	led_trigger_event(nand_led_trigger, LED_FULL);
>  
> @@ -912,6 +897,135 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
>  	return status;
>  }
>  
> +#define BITS_PER_BYTE 8
> +
> +/**
> + * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
> + * @buf: buffer to test
> + * @len: buffer length
> + * @bitflips_threshold: maximum number of bitflips
> + *
> + * Check if a buffer contains only 0xff, which means the underlying region
> + * has been erased and is ready to be programmed.
> + * The bitflips_threshold specify the maximum number of bitflips before
> + * considering the region is not erased.
> + * Note: The logic of this function has been extracted from the memweight
> + * implementation, except that nand_check_erased_buf function exit before
> + * testing the whole buffer if the number of bitflips exceed the
> + * bitflips_threshold value.
> + *
> + * Returns a positive number of bitflips less than or equal to
> + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
> + * threshold.
> + */
> +static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
> +{
> +	const unsigned char *bitmap = buf;
> +	int bitflips = 0;
> +	int weight;
> +
> +	for (; len && ((uintptr_t)bitmap) % sizeof(long);
> +	     len--, bitmap++) {
> +		weight = hweight8(*bitmap);
> +		bitflips += BITS_PER_BYTE - weight;
> +		if (unlikely(bitflips > bitflips_threshold))
> +			return -EBADMSG;
> +	}
> +
> +	for (; len >= 4; len -= 4, bitmap += 4) {
> +		weight = hweight32(*((u32 *)bitmap));
> +		bitflips += 32 - weight;
> +		if (unlikely(bitflips > bitflips_threshold))
> +			return -EBADMSG;
> +	}
> +
> +	for (; len > 0; len--, bitmap++) {
> +		weight = hweight8(*bitmap);
> +		bitflips += BITS_PER_BYTE - weight;
> +		if (unlikely(bitflips > bitflips_threshold))
> +			return -EBADMSG;
> +	}
> +
> +	return bitflips;
> +}
> +
> +/**
> + * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
> + *				 0xff data
> + * @data: data buffer to test
> + * @datalen: data length
> + * @ecc: ECC buffer
> + * @ecclen: ECC length
> + * @extraoob: extra OOB buffer
> + * @extraooblen: extra OOB length
> + * @bitflips_threshold: maximum number of bitflips
> + *
> + * Check if a data buffer and its associated ECC and OOB data contains only
> + * 0xff pattern, which means the underlying region has been erased and is
> + * ready to be programmed.
> + * The bitflips_threshold specify the maximum number of bitflips before
> + * considering the region as not erased.
> + *
> + * Note:
> + * 1/ ECC algorithms are working on pre-defined block sizes which are usually
> + *    different from the NAND page size. When fixing bitflips, ECC engines will
> + *    report the number of errors per chunk, and the NAND core infrastructure
> + *    expect you to return the maximum number of bitflips for the whole page.
> + *    This is why you should always use this function on a single chunk and
> + *    not on the whole page. After checking each chunk you should update your
> + *    max_bitflips value accordingly.
> + * 2/ When checking for bitflips in erased pages you should not only check
> + *    the payload data but also their associated ECC data, because a user might
> + *    have programmed almost all bits to 1 but a few. In this case, we
> + *    shouldn't consider the chunk as erased, and checking ECC bytes prevent
> + *    this case.
> + * 3/ The extraoob argument is optional, and should be used if some of your OOB
> + *    data are protected by the ECC engine.
> + *    It could also be used if you support subpages and want to attach some
> + *    extra OOB data to an ECC chunk.
> + *
> + * Returns a positive number of bitflips less than or equal to
> + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
> + * threshold. In case of success, the passed buffers are filled with 0xff.
> + */
> +int nand_check_erased_ecc_chunk(void *data, int datalen,
> +				void *ecc, int ecclen,
> +				void *extraoob, int extraooblen,
> +				int bitflips_threshold)
> +{
> +	int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
> +
> +	data_bitflips = nand_check_erased_buf(data, datalen,
> +					      bitflips_threshold);
> +	if (data_bitflips < 0)
> +		return data_bitflips;
> +
> +	bitflips_threshold -= data_bitflips;
> +
> +	ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
> +	if (ecc_bitflips < 0)
> +		return ecc_bitflips;
> +
> +	bitflips_threshold -= ecc_bitflips;
> +
> +	extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
> +						  bitflips_threshold);
> +	if (extraoob_bitflips < 0)
> +		return extraoob_bitflips;
> +
> +	if (data_bitflips)
> +		memset(data, 0xff, datalen);
> +
> +	if (ecc_bitflips)
> +		memset(ecc, 0xff, ecclen);
> +
> +	if (extraoob_bitflips)
> +		memset(extraoob, 0xff, extraooblen);
> +
> +	return data_bitflips + ecc_bitflips + extraoob_bitflips;
> +}
> +EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
> +
>  /**
>   * nand_read_page_raw - [INTERN] read raw page data without ecc
>   * @mtd: mtd info structure
> @@ -1103,6 +1217,16 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
>  
>  		stat = chip->ecc.correct(mtd, p,
>  			&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
> +		if (stat == -EBADMSG &&
> +		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
> +			/* check for empty pages with bitflips */
> +			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
> +						&chip->buffers->ecccode[i],
> +						chip->ecc.bytes,
> +						NULL, 0,
> +						chip->ecc.strength);
> +		}
> +
>  		if (stat < 0) {
>  			mtd->ecc_stats.failed++;
>  		} else {
> @@ -1152,6 +1276,15 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
>  		int stat;
>  
>  		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
> +		if (stat == -EBADMSG &&
> +		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
> +			/* check for empty pages with bitflips */
> +			stat = nand_check_erased_ecc_chunk(p, eccsize,
> +						&ecc_code[i], eccbytes,
> +						NULL, 0,
> +						chip->ecc.strength);
> +		}
> +
>  		if (stat < 0) {
>  			mtd->ecc_stats.failed++;
>  		} else {
> @@ -1204,6 +1337,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
>  		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
>  
>  		stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
> +		if (stat == -EBADMSG &&
> +		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
> +			/* check for empty pages with bitflips */
> +			stat = nand_check_erased_ecc_chunk(p, eccsize,
> +						&ecc_code[i], eccbytes,
> +						NULL, 0,
> +						chip->ecc.strength);
> +		}
> +
>  		if (stat < 0) {
>  			mtd->ecc_stats.failed++;
>  		} else {
> @@ -1231,6 +1373,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
>  	int i, eccsize = chip->ecc.size;
>  	int eccbytes = chip->ecc.bytes;
>  	int eccsteps = chip->ecc.steps;
> +	int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
>  	uint8_t *p = buf;
>  	uint8_t *oob = chip->oob_poi;
>  	unsigned int max_bitflips = 0;
> @@ -1250,19 +1393,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
>  		chip->read_buf(mtd, oob, eccbytes);
>  		stat = chip->ecc.correct(mtd, p, oob, NULL);
>  
> -		if (stat < 0) {
> -			mtd->ecc_stats.failed++;
> -		} else {
> -			mtd->ecc_stats.corrected += stat;
> -			max_bitflips = max_t(unsigned int, max_bitflips, stat);
> -		}
> -
>  		oob += eccbytes;
>  
>  		if (chip->ecc.postpad) {
>  			chip->read_buf(mtd, oob, chip->ecc.postpad);
>  			oob += chip->ecc.postpad;
>  		}
> +
> +		if (stat == -EBADMSG &&
> +		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
> +			/* check for empty pages with bitflips */
> +			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
> +							   oob - eccpadbytes,
> +							   eccpadbytes,
> +							   NULL, 0,
> +							   chip->ecc.strength);
> +		}
> +
> +		if (stat < 0) {
> +			mtd->ecc_stats.failed++;
> +		} else {
> +			mtd->ecc_stats.corrected += stat;
> +			max_bitflips = max_t(unsigned int, max_bitflips, stat);
> +		}
>  	}
>  
>  	/* Calculate remaining oob bytes */
> @@ -1361,8 +1514,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
>  	int ret = 0;
>  	uint32_t readlen = ops->len;
>  	uint32_t oobreadlen = ops->ooblen;
> -	uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?
> -		mtd->oobavail : mtd->oobsize;
> +	uint32_t max_oobsize = mtd_oobavail(mtd, ops);
>  
>  	uint8_t *bufpoi, *oob, *buf;
>  	int use_bufpoi;
> @@ -1712,10 +1864,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;
> -	else
> -		len = mtd->oobsize;
> +	len = mtd_oobavail(mtd, ops);
>  
>  	if (unlikely(ops->ooboffs >= len)) {
>  		pr_debug("%s: attempt to start read outside oob\n",
> @@ -1845,8 +1994,7 @@ out:
>   * Not for syndrome calculating ECC controllers, which use a special oob layout.
>   */
>  static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
> -				const uint8_t *buf, int oob_required,
> -				int page)
> +			       const uint8_t *buf, int oob_required, int page)
>  {
>  	chip->write_buf(mtd, buf, mtd->writesize);
>  	if (oob_required)
> @@ -1861,6 +2009,7 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
>   * @chip: nand chip info structure
>   * @buf: data buffer
>   * @oob_required: must write chip->oob_poi to OOB
> + * @page: page number to write
>   *
>   * We need a special oob layout and handling even when ECC isn't checked.
>   */
> @@ -1907,8 +2056,8 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
>   * @page: page number to write
>   */
>  static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
> -				  const uint8_t *buf, int oob_required,
> -				  int page)
> +				 const uint8_t *buf, int oob_required,
> +				 int page)
>  {
>  	int i, eccsize = chip->ecc.size;
>  	int eccbytes = chip->ecc.bytes;
> @@ -2029,6 +2178,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
>   * @chip: nand chip info structure
>   * @buf: data buffer
>   * @oob_required: must write chip->oob_poi to OOB
> + * @page: page number to write
>   *
>   * The hw generator calculates the error syndrome automatically. Therefore we
>   * need a special oob layout and handling.
> @@ -2103,7 +2253,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
>  						  oob_required, page);
>  	else if (subpage)
>  		status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
> -						  buf, oob_required, page);
> +						 buf, oob_required, page);
>  	else
>  		status = chip->ecc.write_page(mtd, chip, buf, oob_required,
>  					      page);
> @@ -2145,7 +2295,6 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
>   * @oob: oob data buffer
>   * @len: oob data write length
>   * @ops: oob ops structure
> - * @page: page number to write
>   */
>  static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
>  			      struct mtd_oob_ops *ops)
> @@ -2214,8 +2363,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
>  	uint32_t writelen = ops->len;
>  
>  	uint32_t oobwritelen = ops->ooblen;
> -	uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?
> -				mtd->oobavail : mtd->oobsize;
> +	uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
>  
>  	uint8_t *oob = ops->oobbuf;
>  	uint8_t *buf = ops->datbuf;
> @@ -2404,10 +2552,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
>  	pr_debug("%s: to = 0x%08x, len = %i\n",
>  			 __func__, (unsigned int)to, (int)ops->ooblen);
>  
> -	if (ops->mode == MTD_OPS_AUTO_OOB)
> -		len = chip->ecc.layout->oobavail;
> -	else
> -		len = mtd->oobsize;
> +	len = mtd_oobavail(mtd, ops);
>  
>  	/* Do not allow write past end of page */
>  	if ((ops->ooboffs + ops->ooblen) > len) {
> @@ -2597,7 +2742,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
>  
>  		/* Check if we have a bad block, we do not erase bad blocks! */
>  		if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) <<
> -					chip->page_shift, 0, allowbbt)) {
> +					chip->page_shift, allowbbt)) {
>  			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
>  				    __func__, page);
>  			instr->state = MTD_ERASE_FAILED;
> @@ -2684,7 +2829,20 @@ static void nand_sync(struct mtd_info *mtd)
>   */
>  static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
>  {
> -	return nand_block_checkbad(mtd, offs, 1, 0);
> +	struct nand_chip *chip = mtd_to_nand(mtd);
> +	int chipnr = (int)(offs >> chip->chip_shift);
> +	int ret;
> +
> +	/* Select the NAND device */
> +	nand_get_device(mtd, FL_READING);
> +	chip->select_chip(mtd, chipnr);
> +
> +	ret = nand_block_checkbad(mtd, offs, 0);
> +
> +	chip->select_chip(mtd, -1);
> +	nand_release_device(mtd);
> +
> +	return ret;
>  }
>  
>  /**
> @@ -2756,9 +2914,6 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
>  		return -EINVAL;
>  #endif
>  
> -	/* clear the sub feature parameters */
> -	memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
> -
>  	chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
>  	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
>  		*subfeature_param++ = chip->read_byte(mtd);
> @@ -3491,7 +3646,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
>  			if (find_full_id_nand(mtd, chip, type, id_data, &busw))
>  				goto ident_done;
>  		} else if (*dev_id == type->dev_id) {
> -				break;
> +			break;
>  		}
>  	}
>  
> @@ -3514,10 +3669,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
>  
>  	chip->chipsize = (uint64_t)type->chipsize << 20;
>  
> -	if (!type->pagesize && chip->init_size) {
> -		/* Set the pagesize, oobsize, erasesize by the driver */
> -		busw = chip->init_size(mtd, chip, id_data);
> -	} else if (!type->pagesize) {
> +	if (!type->pagesize) {
>  		/* Decode parameters from extended ID */
>  		nand_decode_ext_id(mtd, chip, id_data, &busw);
>  	} else {
> @@ -3621,7 +3773,6 @@ ident_done:
>   * This is the first phase of the normal nand_scan() function. It reads the
>   * flash ID and sets up MTD fields accordingly.
>   *
> - * The mtd->owner field must be set to the module of the caller.
>   */
>  int nand_scan_ident(struct mtd_info *mtd, int maxchips,
>  		    struct nand_flash_dev *table)
> @@ -3797,7 +3948,7 @@ int nand_scan_tail(struct mtd_info *mtd)
>  			ecc->write_oob = nand_write_oob_std;
>  		if (!ecc->read_subpage)
>  			ecc->read_subpage = nand_read_subpage;
> -		if (!ecc->write_subpage)
> +		if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
>  			ecc->write_subpage = nand_write_subpage_hwecc;
>  
>  	case NAND_ECC_HW_SYNDROME:
> @@ -3875,10 +4026,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();
> @@ -3913,11 +4062,11 @@ 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;
> +	if (ecc->layout) {
> +		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))
> @@ -4002,18 +4151,6 @@ int nand_scan_tail(struct mtd_info *mtd)
>  }
>  EXPORT_SYMBOL(nand_scan_tail);
>  
> -/*
> - * is_module_text_address() isn't exported, and it's mostly a pointless
> - * test if this is a module _anyway_ -- they'd have to try _really_ hard
> - * to call us from in-kernel code if the core NAND support is modular.
> - */
> -#ifdef MODULE
> -#define caller_is_module() (1)
> -#else
> -#define caller_is_module() \
> -	is_module_text_address((unsigned long)__builtin_return_address(0))
> -#endif
> -
>  /**
>   * nand_scan - [NAND Interface] Scan for the NAND device
>   * @mtd: MTD device structure
> @@ -4021,19 +4158,12 @@ EXPORT_SYMBOL(nand_scan_tail);
>   *
>   * This fills out all the uninitialized function pointers with the defaults.
>   * The flash ID is read and the mtd/chip structures are filled with the
> - * appropriate values. The mtd->owner field must be set to the module of the
> - * caller.
> + * appropriate values.
>   */
>  int nand_scan(struct mtd_info *mtd, int maxchips)
>  {
>  	int ret;
>  
> -	/* Many callers got this wrong, so check for it for a while... */
> -	if (!mtd->owner && caller_is_module()) {
> -		pr_crit("%s called with NULL mtd->owner!\n", __func__);
> -		BUG();
> -	}
> -
>  	ret = nand_scan_ident(mtd, maxchips, NULL);
>  	if (!ret)
>  		ret = nand_scan_tail(mtd);
> @@ -4041,9 +4171,6 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
>  }
>  EXPORT_SYMBOL(nand_scan);
>  
> -module_init(nand_base_init);
> -module_exit(nand_base_exit);
> -
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Steven J. Hill <sjhill at realitydiluted.com>");
>  MODULE_AUTHOR("Thomas Gleixner <tglx at linutronix.de>");
> diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
> index 152f3bc..74c4c9a 100644
> --- a/drivers/mtd/nand/nand_bbt.c
> +++ b/drivers/mtd/nand/nand_bbt.c
> @@ -1,6 +1,4 @@
>  /*
> - *  drivers/mtd/nand_bbt.c
> - *
>   *  Overview:
>   *   Bad block table support for the NAND driver
>   *
> @@ -65,7 +63,6 @@
>  #include <linux/mtd/mtd.h>
>  #include <linux/mtd/bbm.h>
>  #include <linux/mtd/nand.h>
> -#include <linux/mtd/nand_ecc.h>
>  #include <linux/bitops.h>
>  #include <linux/string.h>
>  
> @@ -718,7 +715,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
>  		/* Must we save the block contents? */
>  		if (td->options & NAND_BBT_SAVECONTENT) {
>  			/* Make it block aligned */
> -			to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));
> +			to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1);
>  			len = 1 << this->bbt_erase_shift;
>  			res = mtd_read(mtd, to, len, &retlen, buf);
>  			if (res < 0) {
> @@ -1073,15 +1070,15 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
>   * The bad block table memory is allocated here. It must be freed by calling
>   * the nand_free_bbt function.
>   */
> -int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
> +static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
>  {
>  	struct nand_chip *this = mtd_to_nand(mtd);
> -	int len, res = 0;
> +	int len, res;
>  	uint8_t *buf;
>  	struct nand_bbt_descr *td = this->bbt_td;
>  	struct nand_bbt_descr *md = this->bbt_md;
>  
> -	len = mtd->size >> (this->bbt_erase_shift + 2);
> +	len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
>  	/*
>  	 * Allocate memory (2bit per block) and clear the memory bad block
>  	 * table.
> @@ -1097,10 +1094,9 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
>  	if (!td) {
>  		if ((res = nand_memory_bbt(mtd, bd))) {
>  			pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
> -			kfree(this->bbt);
> -			this->bbt = NULL;
> +			goto err;
>  		}
> -		return res;
> +		return 0;
>  	}
>  	verify_bbt_descr(mtd, td);
>  	verify_bbt_descr(mtd, md);
> @@ -1110,9 +1106,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
>  	len += (len >> this->page_shift) * mtd->oobsize;
>  	buf = vmalloc(len);
>  	if (!buf) {
> -		kfree(this->bbt);
> -		this->bbt = NULL;
> -		return -ENOMEM;
> +		res = -ENOMEM;
> +		goto err;
>  	}
>  
>  	/* Is the bbt at a given page? */
> @@ -1124,6 +1119,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
>  	}
>  
>  	res = check_create(mtd, buf, bd);
> +	if (res)
> +		goto err;
>  
>  	/* Prevent the bbt regions from erasing / writing */
>  	mark_bbt_region(mtd, td);
> @@ -1131,6 +1128,11 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
>  		mark_bbt_region(mtd, md);
>  
>  	vfree(buf);
> +	return 0;
> +
> +err:
> +	kfree(this->bbt);
> +	this->bbt = NULL;
>  	return res;
>  }
>  
> @@ -1369,5 +1371,3 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
>  
>  	return ret;
>  }
> -
> -EXPORT_SYMBOL(nand_scan_bbt);
> diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
> index d7f6ce0..c145203 100644
> --- a/drivers/mtd/nand/nand_bch.c
> +++ b/drivers/mtd/nand/nand_bch.c
> @@ -86,7 +86,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
>  		}
>  	} else if (count < 0) {
>  		printk(KERN_ERR "ecc unrecoverable error\n");
> -		count = -1;
> +		count = -EBADMSG;
>  	}
>  	return count;
>  }
> @@ -94,9 +94,6 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
>  /**
>   * 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
> @@ -110,14 +107,21 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
>   * @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");
> @@ -145,7 +149,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) {
> @@ -171,7 +175,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 */
> @@ -179,7 +183,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;
>  	}
> @@ -203,6 +207,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/nand_ids.c b/drivers/mtd/nand/nand_ids.c
> index fdd0074..561d2cd 100644
> --- a/drivers/mtd/nand/nand_ids.c
> +++ b/drivers/mtd/nand/nand_ids.c
> @@ -1,6 +1,4 @@
>  /*
> - *  drivers/mtd/nandids.c
> - *
>   *  Copyright (C) 2002 Thomas Gleixner (tglx at linutronix.de)
>   *
>   * This program is free software; you can redistribute it and/or modify
> @@ -41,6 +39,10 @@ struct nand_flash_dev nand_flash_ids[] = {
>  	 * listed by full ID. We list them first so that we can easily identify
>  	 * the most specific match.
>  	 */
> +	{"TC58NVG0S3E 1G 3.3V 8-bit",
> +		{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
> +		  SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512),
> +		  2 },
>  	{"TC58NVG2S0F 4G 3.3V 8-bit",
>  		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
>  		  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
> @@ -58,8 +60,8 @@ struct nand_flash_dev nand_flash_ids[] = {
>  		  SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
>  	{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
>  		{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
> -		  SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
> -		  4 },
> +		  SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
> +		  NAND_ECC_INFO(40, SZ_1K), 4 },
>  
>  	LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
>  	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
> diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
> index ee353c7..0a9849e 100644
> --- a/drivers/mtd/nand/ndfc.c
> +++ b/drivers/mtd/nand/ndfc.c
> @@ -1,6 +1,6 @@
>  /*
>   * Overview:
> - *   Platform independend driver for NDFC (NanD Flash Controller)
> + *   Platform independent driver for NDFC (NanD Flash Controller)
>   *   integrated into IBM/AMCC PPC4xx cores
>   *
>   * (C) Copyright 2006-2009
> diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
> index cac9eea..37c4341 100644
> --- a/drivers/mtd/nand/omap_gpmc.c
> +++ b/drivers/mtd/nand/omap_gpmc.c
> @@ -163,7 +163,7 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
>  				return 0;
>  			printf("Error: Bad compare! failed\n");
>  			/* detected 2 bit error */
> -			return -1;
> +			return -EBADMSG;
>  		}
>  	}
>  	return 0;
> diff --git a/drivers/mtd/nand/s3c2410_nand.c b/drivers/mtd/nand/s3c2410_nand.c
> index 2a0da6e..dd742a6 100644
> --- a/drivers/mtd/nand/s3c2410_nand.c
> +++ b/drivers/mtd/nand/s3c2410_nand.c
> @@ -104,7 +104,7 @@ static int s3c24x0_nand_correct_data(struct mtd_info *mtd, u_char *dat,
>  		return 0;
>  
>  	printf("s3c24x0_nand_correct_data: not implemented\n");
> -	return -1;
> +	return -EBADMSG;
>  }
>  #endif
>  
> diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
> index dfbefc6..f99bdaf 100644
> --- a/drivers/mtd/nand/vf610_nfc.c
> +++ b/drivers/mtd/nand/vf610_nfc.c
> @@ -146,7 +146,6 @@ enum vf610_nfc_alt_buf {
>  };
>  
>  struct vf610_nfc {
> -	struct mtd_info *mtd;
>  	struct nand_chip chip;
>  	void __iomem *regs;
>  	uint buf_offset;
> diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> index 9da77ec..cf20674 100644
> --- a/include/linux/mtd/mtd.h
> +++ b/include/linux/mtd/mtd.h
> @@ -278,6 +278,11 @@ struct mtd_info {
>  	int usecount;
>  };
>  
> +static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
> +{
> +	return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
> +}
> +
>  int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
>  #ifndef __UBOOT__
>  int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
> diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
> index 34945fd..b5a02c3 100644
> --- a/include/linux/mtd/nand.h
> +++ b/include/linux/mtd/nand.h
> @@ -25,6 +25,8 @@
>  
>  struct mtd_info;
>  struct nand_flash_dev;
> +struct device_node;
> +
>  /* Scan and identify a NAND device */
>  extern int nand_scan(struct mtd_info *mtd, int max_chips);
>  /*
> @@ -144,6 +146,14 @@ typedef enum {
>  /* Enable Hardware ECC before syndrome is read back from flash */
>  #define NAND_ECC_READSYN	2
>  
> +/*
> + * Enable generic NAND 'page erased' check. This check is only done when
> + * ecc.correct() returns -EBADMSG.
> + * Set this flag if your implementation does not fix bitflips in erased
> + * pages and you want to rely on the default implementation.
> + */
> +#define NAND_ECC_GENERIC_ERASED_CHECK	BIT(0)
> +
>  /* Bit mask for flags passed to do_nand_read_ecc */
>  #define NAND_GET_DEVICE		0x80
>  
> @@ -179,6 +189,12 @@ typedef enum {
>  /* Device supports subpage reads */
>  #define NAND_SUBPAGE_READ	0x00001000
>  
> +/*
> + * Some MLC NANDs need data scrambling to limit bitflips caused by repeated
> + * patterns.
> + */
> +#define NAND_NEED_SCRAMBLING	0x00002000
> +
>  /* Options valid for Samsung large page devices */
>  #define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
>  
> @@ -203,6 +219,11 @@ typedef enum {
>   * before calling nand_scan_tail.
>   */
>  #define NAND_BUSWIDTH_AUTO      0x00080000
> +/*
> + * This option could be defined by controller drivers to protect against
> + * kmap'ed, vmalloc'ed highmem buffers being passed from upper layers
> + */
> +#define NAND_USE_BOUNCE_BUFFER	0x00100000
>  
>  /* Options set by nand scan */
>  /* bbt has already been read */
> @@ -292,15 +313,15 @@ struct nand_onfi_params {
>  	__le16 t_r;
>  	__le16 t_ccs;
>  	__le16 src_sync_timing_mode;
> -	__le16 src_ssync_features;
> +	u8 src_ssync_features;
>  	__le16 clk_pin_capacitance_typ;
>  	__le16 io_pin_capacitance_typ;
>  	__le16 input_pin_capacitance_typ;
>  	u8 input_pin_capacitance_max;
>  	u8 driver_strength_support;
>  	__le16 t_int_r;
> -	__le16 t_ald;
> -	u8 reserved4[7];
> +	__le16 t_adl;
> +	u8 reserved4[8];
>  
>  	/* vendor */
>  	__le16 vendor_revision;
> @@ -423,7 +444,7 @@ struct nand_jedec_params {
>  	__le16 input_pin_capacitance_typ;
>  	__le16 clk_pin_capacitance_typ;
>  	u8 driver_strength_support;
> -	__le16 t_ald;
> +	__le16 t_adl;
>  	u8 reserved4[36];
>  
>  	/* ECC and endurance block */
> @@ -466,12 +487,19 @@ struct nand_hw_control {
>   * @total:	total number of ECC bytes per page
>   * @prepad:	padding information for syndrome based ECC generators
>   * @postpad:	padding information for syndrome based ECC generators
> + * @options:	ECC specific options (see NAND_ECC_XXX flags defined above)
>   * @layout:	ECC layout control struct pointer
>   * @priv:	pointer to private ECC control data
>   * @hwctl:	function to control hardware ECC generator. Must only
>   *		be provided if an hardware ECC is available
>   * @calculate:	function for ECC calculation or readback from ECC hardware
> - * @correct:	function for ECC correction, matching to ECC generator (sw/hw)
> + * @correct:	function for ECC correction, matching to ECC generator (sw/hw).
> + *		Should return a positive number representing the number of
> + *		corrected bitflips, -EBADMSG if the number of bitflips exceed
> + *		ECC strength, or any other error code if the error is not
> + *		directly related to correction.
> + *		If -EBADMSG is returned the input buffers should be left
> + *		untouched.
>   * @read_page_raw:	function to read a raw page without ECC. This function
>   *			should hide the specific layout used by the ECC
>   *			controller and always return contiguous in-band and
> @@ -509,6 +537,7 @@ struct nand_ecc_ctrl {
>  	int strength;
>  	int prepad;
>  	int postpad;
> +	unsigned int options;
>  	struct nand_ecclayout	*layout;
>  	void *priv;
>  	void (*hwctl)(struct mtd_info *mtd, int mode);
> @@ -556,6 +585,7 @@ struct nand_buffers {
>  
>  /**
>   * struct nand_chip - NAND Private Flash Chip Data
> + * @mtd:		MTD device registered to the MTD framework
>   * @IO_ADDR_R:		[BOARDSPECIFIC] address to read the 8 I/O lines of the
>   *			flash device
>   * @IO_ADDR_W:		[BOARDSPECIFIC] address to write the 8 I/O lines of the
> @@ -571,10 +601,6 @@ struct nand_buffers {
>   * @block_markbad:	[REPLACEABLE] mark a block bad
>   * @cmd_ctrl:		[BOARDSPECIFIC] hardwarespecific function for controlling
>   *			ALE/CLE/nCE. Also used to write command and address
> - * @init_size:		[BOARDSPECIFIC] hardwarespecific function for setting
> - *			mtd->oobsize, mtd->writesize and so on.
> - *			@id_data contains the 8 bytes values of NAND_CMD_READID.
> - *			Return with the bus width.
>   * @dev_ready:		[BOARDSPECIFIC] hardwarespecific function for accessing
>   *			device ready/busy line. If set to NULL no access to
>   *			ready/busy is available and the ready/busy information
> @@ -669,11 +695,9 @@ struct nand_chip {
>  	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
>  	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
>  	void (*select_chip)(struct mtd_info *mtd, int chip);
> -	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
> +	int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
>  	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
>  	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
> -	int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
> -			u8 *id_data);
>  	int (*dev_ready)(struct mtd_info *mtd);
>  	void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
>  			int page_addr);
> @@ -873,7 +897,6 @@ struct nand_manufacturers {
>  extern struct nand_flash_dev nand_flash_ids[];
>  extern struct nand_manufacturers nand_manuf_ids[];
>  
> -extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
>  extern int nand_default_bbt(struct mtd_info *mtd);
>  extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
>  extern int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
> @@ -898,7 +921,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 {
> @@ -906,7 +928,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;
> @@ -955,15 +976,6 @@ struct platform_nand_data {
>  	struct platform_nand_ctrl ctrl;
>  };
>  
> -/* Some helpers to access the data structures */
> -static inline
> -struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
> -{
> -	struct nand_chip *chip = mtd->priv;
> -
> -	return chip->priv;
> -}
> -
>  #ifdef CONFIG_SYS_NAND_ONFI_DETECTION
>  /* return the supported features. */
>  static inline int onfi_feature(struct nand_chip *chip)
> @@ -1081,4 +1093,9 @@ struct nand_sdr_timings {
>  
>  /* get timing characteristics from ONFI timing mode. */
>  const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
> +
> +int nand_check_erased_ecc_chunk(void *data, int datalen,
> +				void *ecc, int ecclen,
> +				void *extraoob, int extraooblen,
> +				int threshold);
>  #endif /* __LINUX_MTD_NAND_H */
> diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h
> index d8754dd..8ea6b04 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
>   */
> @@ -55,12 +53,10 @@ static inline int
>  nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
>  		      unsigned char *read_ecc, unsigned char *calc_ecc)
>  {
> -	return -1;
> +	return -ENOTSUPP;
>  }
>  
> -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;
>  }



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


More information about the U-Boot mailing list