diff options
author | Scott Wood <oss@buserror.net> | 2016-05-30 18:57:58 (GMT) |
---|---|---|
committer | Scott Wood <oss@buserror.net> | 2016-06-04 01:27:48 (GMT) |
commit | ceee07b65875bb01bef55cba06940ef7afc1afba (patch) | |
tree | 114c79852874d1970e91ff76f80835ce25038baa /drivers/mtd/nand | |
parent | 81c772521ff26054a3fe75efa87d8daeae83e9b4 (diff) | |
download | u-boot-ceee07b65875bb01bef55cba06940ef7afc1afba.tar.xz |
mtd: nand: Sync with Linux v4.6
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.
Signed-off-by: Scott Wood <oss@buserror.net>
Tested-by: Heiko Schocher <hs@denx.de>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/davinci_nand.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/denali.c | 39 | ||||
-rw-r--r-- | drivers/mtd/nand/denali.h | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/denali_spl.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/mpc5121_nfc.c | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 5 | ||||
-rw-r--r-- | drivers/mtd/nand/mxc_nand_spl.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/mxs_nand.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 329 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 30 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bch.c | 29 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ids.c | 10 | ||||
-rw-r--r-- | drivers/mtd/nand/ndfc.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/omap_gpmc.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/s3c2410_nand.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/vf610_nfc.c | 1 |
17 files changed, 298 insertions, 171 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@realitydiluted.com>"); MODULE_AUTHOR("Thomas Gleixner <tglx@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@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; |