diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-29 11:11:56 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-29 11:11:56 -0800 |
commit | 0fc7e74663447682c904fe375bb680b004ddaa14 (patch) | |
tree | 95f89c4a207995e57354c4f44bf7d83b5536370c /drivers/mtd | |
parent | aa5e75bc7a7c4ecbdee7bc85d1a306041b926e24 (diff) | |
parent | 571cb17b23eccc22f18c4fc0a0fc34cf0abca7ef (diff) |
Merge tag 'mtd/for-4.16' of git://git.infradead.org/linux-mtd
Pull MTD updates from Boris Brezillon:
"MTD core changes:
- Rework core functions to avoid duplicating generic checks in
NAND/OneNAND sub-layers
- Update the MAINTAINERS entry to reflect the fact that MTD
maintainers now use a single git tree
MTD driver changes:
- CFI: use macros instead of inline functions to limit stack usage
and make KASAN happy
NAND core changes:
- Fix NAND_CMD_NONE handling in nand_command[_lp]() hooks
- Introduce the ->exec_op() infrastructure
- Rework NAND buffers handling
- Fix ECC requirements for K9F4G08U0D
- Fix nand_do_read_oob() to return the number of bitflips
- Mark K9F1G08U0E as not supporting subpage writes
NAND driver changes:
- MTK: Rework the driver to support new IP versions
- OMAP OneNAND: Full rework to use new APIs (libgpio, dmaengine) and
fix DT support
- Marvell: Add a new driver to replace the pxa3xx one
SPI NOR core changes:
- Add support to new ISSI and Cypress/Spansion memory parts.
- Fix support of Micron memories by checking error bits in the FSR.
- Fix update of block-protection bits by reading back the SR.
- Restore the internal state of the SPI flash memory when removing
the device.
SPI NOR driver changes:
- Maintenance for Freescale, Intel and Metiatek drivers.
- Add support of the direct access mode for the Cadence QSPI
controller"
* tag 'mtd/for-4.16' of git://git.infradead.org/linux-mtd: (93 commits)
mtd: nand: sunxi: Fix ECC strength choice
mtd: nand: gpmi: Fix subpage reads
mtd: nand: Fix build issues due to an anonymous union
mtd: nand: marvell: Fix missing memory allocation modifier
mtd: nand: marvell: remove redundant variable 'oob_len'
mtd: nand: marvell: fix spelling mistake: "suceed"-> "succeed"
mtd: onenand: omap2: Remove redundant dev_err call in omap2_onenand_probe()
mtd: Remove duplicate checks on mtd_oob_ops parameter
mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
mtd: mtdpart: Make ECC stat handling consistent
mtd: onenand: omap2: print resource using %pR format string
mtd: mtk-nor: modify functions' name more generally
mtd: onenand: samsung: remove incorrect __iomem annotation
MAINTAINERS: Add entry for Marvell NAND controller driver
ARM: OMAP2+: Remove gpmc-onenand
mtd: onenand: omap2: Configure driver from DT
mtd: onenand: omap2: Decouple DMA enabling from INT pin availability
mtd: onenand: omap2: Do not make delay for GPIO OMAP3 specific
mtd: onenand: omap2: Convert to use dmaengine for memcpy
mtd: onenand: omap2: Unify OMAP2 and OMAP3 DMA implementation
...
Diffstat (limited to 'drivers/mtd')
58 files changed, 6033 insertions, 1809 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 0806f72102c0..a85af236b44d 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -904,9 +904,6 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, if (ooblen % DOC_LAYOUT_OOB_SIZE) return -EINVAL; - if (from + len > mtd->size) - return -EINVAL; - ops->oobretlen = 0; ops->retlen = 0; ret = 0; @@ -990,36 +987,6 @@ err_in_read: goto out; } -/** - * doc_read - Read bytes from flash - * @mtd: the device - * @from: the offset from first block and first page, in bytes, aligned on page - * size - * @len: the number of bytes to read (must be a multiple of 4) - * @retlen: the number of bytes actually read - * @buf: the filled in buffer - * - * Reads flash memory pages. This function does not read the OOB chunk, but only - * the page data. - * - * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred - */ -static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - struct mtd_oob_ops ops; - size_t ret; - - memset(&ops, 0, sizeof(ops)); - ops.datbuf = buf; - ops.len = len; - ops.mode = MTD_OPS_AUTO_OOB; - - ret = doc_read_oob(mtd, from, &ops); - *retlen = ops.retlen; - return ret; -} - static int doc_reload_bbt(struct docg3 *docg3) { int block = DOC_LAYOUT_BLOCK_BBT; @@ -1471,8 +1438,6 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, if (len && ooblen && (len / DOC_LAYOUT_PAGE_SIZE) != (ooblen / oobdelta)) return -EINVAL; - if (ofs + len > mtd->size) - return -EINVAL; ops->oobretlen = 0; ops->retlen = 0; @@ -1513,39 +1478,6 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, return ret; } -/** - * doc_write - Write a buffer to the chip - * @mtd: the device - * @to: the offset from first block and first page, in bytes, aligned on page - * size - * @len: the number of bytes to write (must be a full page size, ie. 512) - * @retlen: the number of bytes actually written (0 or 512) - * @buf: the buffer to get bytes from - * - * Writes data to the chip. - * - * Returns 0 if write successful, -EIO if write error - */ -static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - struct docg3 *docg3 = mtd->priv; - int ret; - struct mtd_oob_ops ops; - - doc_dbg("doc_write(to=%lld, len=%zu)\n", to, len); - ops.datbuf = (char *)buf; - ops.len = len; - ops.mode = MTD_OPS_PLACE_OOB; - ops.oobbuf = NULL; - ops.ooblen = 0; - ops.ooboffs = 0; - - ret = doc_write_oob(mtd, to, &ops); - *retlen = ops.retlen; - return ret; -} - static struct docg3 *sysfs_dev2docg3(struct device *dev, struct device_attribute *attr) { @@ -1866,8 +1798,6 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) mtd->writebufsize = mtd->writesize = DOC_LAYOUT_PAGE_SIZE; mtd->oobsize = DOC_LAYOUT_OOB_SIZE; mtd->_erase = doc_erase; - mtd->_read = doc_read; - mtd->_write = doc_write; mtd->_read_oob = doc_read_oob; mtd->_write_oob = doc_write_oob; mtd->_block_isbad = doc_block_isbad; diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index dbe6a1de2bb8..a4e18f6aaa33 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi) { struct m25p *flash = spi_get_drvdata(spi); + spi_nor_restore(&flash->spi_nor); + /* Clean up MTD stuff. */ return mtd_device_unregister(&flash->spi_nor.mtd); } +static void m25p_shutdown(struct spi_device *spi) +{ + struct m25p *flash = spi_get_drvdata(spi); + + spi_nor_restore(&flash->spi_nor); +} /* * Do NOT add to this array without reading the following: * @@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = { .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, + .shutdown = m25p_shutdown, /* REVISIT: many of these chips have deep power-down modes, which * should clearly be entered on suspend() to minimize power use. diff --git a/drivers/mtd/devices/mchp23k256.c b/drivers/mtd/devices/mchp23k256.c index 8956b7dcc984..75f71d166fd6 100644 --- a/drivers/mtd/devices/mchp23k256.c +++ b/drivers/mtd/devices/mchp23k256.c @@ -68,6 +68,7 @@ static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len, struct spi_transfer transfer[2] = {}; struct spi_message message; unsigned char command[MAX_CMD_SIZE]; + int ret; spi_message_init(&message); @@ -84,12 +85,16 @@ static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len, mutex_lock(&flash->lock); - spi_sync(flash->spi, &message); + ret = spi_sync(flash->spi, &message); + + mutex_unlock(&flash->lock); + + if (ret) + return ret; if (retlen && message.actual_length > sizeof(command)) *retlen += message.actual_length - sizeof(command); - mutex_unlock(&flash->lock); return 0; } @@ -100,6 +105,7 @@ static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_transfer transfer[2] = {}; struct spi_message message; unsigned char command[MAX_CMD_SIZE]; + int ret; spi_message_init(&message); @@ -117,12 +123,16 @@ static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len, mutex_lock(&flash->lock); - spi_sync(flash->spi, &message); + ret = spi_sync(flash->spi, &message); + + mutex_unlock(&flash->lock); + + if (ret) + return ret; if (retlen && message.actual_length > sizeof(command)) *retlen += message.actual_length - sizeof(command); - mutex_unlock(&flash->lock); return 0; } diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 73b605577447..28553c840d32 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -503,6 +503,11 @@ int add_mtd_device(struct mtd_info *mtd) return -EEXIST; BUG_ON(mtd->writesize == 0); + + if (WARN_ON((!mtd->erasesize || !mtd->_erase) && + !(mtd->flags & MTD_NO_ERASE))) + return -EINVAL; + mutex_lock(&mtd_table_mutex); i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL); @@ -1053,7 +1058,20 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, * representing the maximum number of bitflips that were corrected on * any one ecc region (if applicable; zero otherwise). */ - ret_code = mtd->_read(mtd, from, len, retlen, buf); + if (mtd->_read) { + ret_code = mtd->_read(mtd, from, len, retlen, buf); + } else if (mtd->_read_oob) { + struct mtd_oob_ops ops = { + .len = len, + .datbuf = buf, + }; + + ret_code = mtd->_read_oob(mtd, from, &ops); + *retlen = ops.retlen; + } else { + return -ENOTSUPP; + } + if (unlikely(ret_code < 0)) return ret_code; if (mtd->ecc_strength == 0) @@ -1068,11 +1086,25 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, *retlen = 0; if (to < 0 || to >= mtd->size || len > mtd->size - to) return -EINVAL; - if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE)) + if ((!mtd->_write && !mtd->_write_oob) || + !(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (!len) return 0; ledtrig_mtd_activity(); + + if (!mtd->_write) { + struct mtd_oob_ops ops = { + .len = len, + .datbuf = (u8 *)buf, + }; + int ret; + + ret = mtd->_write_oob(mtd, to, &ops); + *retlen = ops.retlen; + return ret; + } + return mtd->_write(mtd, to, len, retlen, buf); } EXPORT_SYMBOL_GPL(mtd_write); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index be088bccd593..76cd21d1171b 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -105,34 +105,17 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { struct mtd_part *part = mtd_to_part(mtd); + struct mtd_ecc_stats stats; int res; - if (from >= mtd->size) - return -EINVAL; - if (ops->datbuf && from + ops->len > mtd->size) - return -EINVAL; - - /* - * If OOB is also requested, make sure that we do not read past the end - * of this partition. - */ - if (ops->oobbuf) { - size_t len, pages; - - len = mtd_oobavail(mtd, ops); - pages = mtd_div_by_ws(mtd->size, mtd); - pages -= mtd_div_by_ws(from, mtd); - if (ops->ooboffs + ops->ooblen > pages * len) - return -EINVAL; - } - + stats = part->parent->ecc_stats; res = part->parent->_read_oob(part->parent, from + part->offset, ops); - if (unlikely(res)) { - if (mtd_is_bitflip(res)) - mtd->ecc_stats.corrected++; - if (mtd_is_eccerr(res)) - mtd->ecc_stats.failed++; - } + if (unlikely(mtd_is_eccerr(res))) + mtd->ecc_stats.failed += + part->parent->ecc_stats.failed - stats.failed; + else + mtd->ecc_stats.corrected += + part->parent->ecc_stats.corrected - stats.corrected; return res; } @@ -189,10 +172,6 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to, { struct mtd_part *part = mtd_to_part(mtd); - if (to >= mtd->size) - return -EINVAL; - if (ops->datbuf && to + ops->len > mtd->size) - return -EINVAL; return part->parent->_write_oob(part->parent, to + part->offset, ops); } @@ -435,8 +414,10 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent, parent->dev.parent; slave->mtd.dev.of_node = part->of_node; - slave->mtd._read = part_read; - slave->mtd._write = part_write; + if (parent->_read) + slave->mtd._read = part_read; + if (parent->_write) + slave->mtd._write = part_write; if (parent->_panic_write) slave->mtd._panic_write = part_panic_write; diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index f07492c6f4b2..7eb0e1f4f980 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1223,8 +1223,9 @@ static int mtdswap_show(struct seq_file *s, void *data) unsigned int max[MTDSWAP_TREE_CNT]; unsigned int i, cw = 0, cwp = 0, cwecount = 0, bb_cnt, mapped, pages; uint64_t use_size; - char *name[] = {"clean", "used", "low", "high", "dirty", "bitflip", - "failing"}; + static const char * const name[] = { + "clean", "used", "low", "high", "dirty", "bitflip", "failing" + }; mutex_lock(&d->mbd_dev->lock); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index bb48aafed9a2..e6b8c59f2c0d 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -315,6 +315,7 @@ config MTD_NAND_ATMEL config MTD_NAND_PXA3xx tristate "NAND support on PXA3xx and Armada 370/XP" + depends on !MTD_NAND_MARVELL depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU help @@ -323,6 +324,18 @@ config MTD_NAND_PXA3xx platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada platforms (7K, 8K) (NFCv2). +config MTD_NAND_MARVELL + tristate "NAND controller support on Marvell boards" + depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \ + COMPILE_TEST + depends on HAS_IOMEM + help + This enables the NAND flash controller driver for Marvell boards, + including: + - PXA3xx processors (NFCv1) + - 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2) + - 64-bit Aramda platforms (7k, 8k) (NFCv2) + config MTD_NAND_SLC_LPC32XX tristate "NXP LPC32xx SLC Controller" depends on ARCH_LPC32XX @@ -376,9 +389,7 @@ config MTD_NAND_GPMI_NAND Enables NAND Flash support for IMX23, IMX28 or IMX6. The GPMI controller is very powerful, with the help of BCH module, it can do the hardware ECC. The GPMI supports several - NAND flashs at the same time. The GPMI may conflicts with other - block, such as SD card. So pay attention to it when you enable - the GPMI. + NAND flashs at the same time. config MTD_NAND_BRCMNAND tristate "Broadcom STB NAND controller" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 118a1349aad3..921634ba400c 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o +obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index 90a71a56bc23..b2f00b398490 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -841,6 +841,8 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf, struct atmel_nand *nand = to_atmel_nand(chip); int ret; + nand_prog_page_begin_op(chip, page, 0, NULL, 0); + ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw); if (ret) return ret; @@ -857,7 +859,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf, atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; + return nand_prog_page_end_op(chip); } static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, @@ -881,6 +883,8 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf, struct mtd_info *mtd = nand_to_mtd(chip); int ret; + nand_read_page_op(chip, page, 0, NULL, 0); + ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw); if (ret) return ret; @@ -1000,7 +1004,7 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf, * to the non-optimized one. */ if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) { - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + nand_read_page_op(chip, page, 0, NULL, 0); return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, raw); @@ -1178,7 +1182,6 @@ static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand) chip->ecc.write_page = atmel_hsmc_nand_pmecc_write_page; chip->ecc.read_page_raw = atmel_hsmc_nand_pmecc_read_page_raw; chip->ecc.write_page_raw = atmel_hsmc_nand_pmecc_write_page_raw; - chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS; return 0; } diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 5655dca6ce43..87bbd177b3e5 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -572,6 +572,8 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + nand_read_page_op(chip, page, 0, NULL, 0); + bf5xx_nand_read_buf(mtd, buf, mtd->writesize); bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -582,10 +584,10 @@ static int bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { - bf5xx_nand_write_buf(mtd, buf, mtd->writesize); + nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; + return nand_prog_page_end_op(chip); } /* diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c index dd56a671ea42..c28fd2bc1a84 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/brcmnand/brcmnand.c @@ -1071,7 +1071,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp) return; brcmnand_set_wp(ctrl, wp); - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + nand_status_op(chip, NULL); /* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */ ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY | @@ -1453,7 +1453,7 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd) /* At FC_BYTES boundary, switch to next column */ if (host->last_byte > 0 && offs == 0) - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, addr, -1); + nand_change_read_column_op(chip, addr, NULL, 0, false); ret = ctrl->flash_cache[offs]; break; @@ -1681,7 +1681,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, int ret; if (!buf) { - buf = chip->buffers->databuf; + buf = chip->data_buf; /* Invalidate page cache */ chip->pagebuf = -1; } @@ -1689,7 +1689,6 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, sas = mtd->oobsize / chip->ecc.steps; /* read without ecc for verification */ - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page); if (ret) return ret; @@ -1793,6 +1792,8 @@ static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip, struct brcmnand_host *host = nand_get_controller_data(chip); u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL; + nand_read_page_op(chip, page, 0, NULL, 0); + return brcmnand_read(mtd, chip, hos |