diff options
-rw-r--r-- | Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 2 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mtd/partitions/redboot-fis.txt | 27 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml | 42 | ||||
-rw-r--r-- | MAINTAINERS | 4 | ||||
-rw-r--r-- | drivers/mtd/Kconfig | 10 | ||||
-rw-r--r-- | drivers/mtd/ftl.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/Kconfig | 23 | ||||
-rw-r--r-- | drivers/mtd/maps/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/maps/pmcmsp-flash.c | 227 | ||||
-rw-r--r-- | drivers/mtd/mtd_blkdevs.c | 60 | ||||
-rw-r--r-- | drivers/mtd/mtdblock.c | 4 | ||||
-rw-r--r-- | drivers/mtd/mtdblock_ro.c | 4 | ||||
-rw-r--r-- | drivers/mtd/mtdconcat.c | 33 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/Kconfig | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/cafe_nand.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/intel-nand-controller.c | 27 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/meson_nand.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/nand_bbt.c | 33 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/omap2.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/spi/core.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/spi/macronix.c | 16 | ||||
-rw-r--r-- | drivers/mtd/rfd_ftl.c | 46 |
22 files changed, 198 insertions, 381 deletions
diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt index 44919d48d241..c459f169a904 100644 --- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt @@ -122,7 +122,7 @@ on various other factors also like; so the device should have enough free bytes available its OOB/Spare area to accommodate ECC for entire page. In general following expression helps in determining if given device can accommodate ECC syndrome: - "2 + (PAGESIZE / 512) * ECC_BYTES" >= OOBSIZE" + "2 + (PAGESIZE / 512) * ECC_BYTES" <= OOBSIZE" where OOBSIZE number of bytes in OOB/spare area PAGESIZE number of bytes in main-area of device page diff --git a/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.txt b/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.txt deleted file mode 100644 index fd0ebe4e3415..000000000000 --- a/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.txt +++ /dev/null @@ -1,27 +0,0 @@ -RedBoot FLASH Image System (FIS) Partitions -=========================================== - -The FLASH Image System (FIS) directory is a flash description -format closely associated with the RedBoot boot loader. - -It uses one single flash eraseblock in the flash to store an index of -all images in the flash. - -This block size will vary depending on flash but is typically -32 KB in size. - -Required properties: -- compatible : (required) must be "redboot-fis" -- fis-index-block : (required) a index to the eraseblock containing - the FIS directory on this device. On a flash memory with 32KB - eraseblocks, 0 means the first eraseblock at 0x00000000, 1 means the - second eraseblock at 0x00008000 and so on. - -Example: - -flash@0 { - partitions { - compatible = "redboot-fis"; - fis-index-block = <0>; - }; -}; diff --git a/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml b/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml new file mode 100644 index 000000000000..fee8d81b5276 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/partitions/redboot-fis.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RedBoot FLASH Image System (FIS) Partitions + +description: The FLASH Image System (FIS) directory is a flash description + format closely associated with the RedBoot boot loader. + It uses one single flash eraseblock in the flash to store an index of + all images in the flash. + This block size will vary depending on flash but is typically + 32 KB in size. + +maintainers: + - Linus Walleij <linus.walleij@linaro.org> + +properties: + compatible: + const: redboot-fis + + fis-index-block: + $ref: /schemas/types.yaml#/definitions/uint32 + description: a index to the eraseblock containing the FIS directory on this + device. On a flash memory with 32KB eraseblocks, 0 means the first + eraseblock at 0x00000000, 1 means the second eraseblock at 0x00008000 and so on. + +required: + - compatible + - fis-index-block + +additionalProperties: false + +examples: + - | + flash { + partitions { + compatible = "redboot-fis"; + fis-index-block = <0>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e4bdea045e85..cfec5dc5a76f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1496,7 +1496,7 @@ F: drivers/amba/ F: include/linux/amba/bus.h ARM PRIMECELL PL35X NAND CONTROLLER DRIVER -M: Miquel Raynal <miquel.raynal@bootlin.com@bootlin.com> +M: Miquel Raynal <miquel.raynal@bootlin.com> M: Naga Sureshkumar Relli <nagasure@xilinx.com> L: linux-mtd@lists.infradead.org S: Maintained @@ -1504,7 +1504,7 @@ F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml F: drivers/mtd/nand/raw/pl35x-nand-controller.c ARM PRIMECELL PL35X SMC DRIVER -M: Miquel Raynal <miquel.raynal@bootlin.com@bootlin.com> +M: Miquel Raynal <miquel.raynal@bootlin.com> M: Naga Sureshkumar Relli <nagasure@xilinx.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 8bab6f8718a9..796a2eccbef0 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -45,10 +45,9 @@ config MTD_BLOCK on RAM chips in this manner. This block device is a user of MTD devices performing that function. - At the moment, it is also required for the Journalling Flash File - System(s) to obtain a handle on the MTD device when it's mounted - (although JFFS and JFFS2 don't actually use any of the functionality - of the mtdblock device). + Note that mounting a JFFS2 filesystem doesn't require using mtdblock. + It's possible to mount a rootfs using the MTD device on the "root=" + bootargs as "root=mtd2" or "root=mtd:name_of_device". Later, it may be extended to perform read/erase/modify/write cycles on flash chips to emulate a smaller block size. Needless to say, @@ -70,6 +69,9 @@ config MTD_BLOCK_RO You do not need this option for use with the DiskOnChip devices. For those, enable NFTL support (CONFIG_NFTL) instead. +comment "Note that in some cases UBI block is preferred. See MTD_UBI_BLOCK." + depends on MTD_BLOCK || MTD_BLOCK_RO + config FTL tristate "FTL (Flash Translation Layer) support" depends on BLOCK diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 9b33c082179d..f655d2905270 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1029,7 +1029,7 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) partition->mbd.tr = tr; partition->mbd.devnum = -1; - if (!add_mtd_blktrans_dev((void *)partition)) + if (!add_mtd_blktrans_dev(&partition->mbd)) return; } diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 6650acbc961e..aaa164b977fe 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -127,29 +127,6 @@ config MTD_PHYSMAP_GPIO_ADDR Extend the physmap driver to allow flashes to be partially physically addressed and assisted by GPIOs. -config MTD_PMC_MSP_EVM - tristate "CFI Flash device mapped on PMC-Sierra MSP" - depends on PMC_MSP && MTD_CFI - help - This provides a 'mapping' driver which supports the way - in which user-programmable flash chips are connected on the - PMC-Sierra MSP eval/demo boards. - -choice - prompt "Maximum mappable memory available for flash IO" - depends on MTD_PMC_MSP_EVM - default MSP_FLASH_MAP_LIMIT_32M - -config MSP_FLASH_MAP_LIMIT_32M - bool "32M" - -endchoice - -config MSP_FLASH_MAP_LIMIT - hex - default "0x02000000" - depends on MSP_FLASH_MAP_LIMIT_32M - config MTD_SUN_UFLASH tristate "Sun Microsystems userflash support" depends on SPARC && MTD_CFI && PCI diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 79f018cf412f..11fea9c8d561 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -25,7 +25,6 @@ physmap-objs-$(CONFIG_MTD_PHYSMAP_IXP4XX) += physmap-ixp4xx.o physmap-objs := $(physmap-objs-y) obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PISMO) += pismo.o -obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c deleted file mode 100644 index 2051f28ddac6..000000000000 --- a/drivers/mtd/maps/pmcmsp-flash.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. - * Config with both CFI and JEDEC device support. - * - * Basically physmap.c with the addition of partitions and - * an array of mapping info to accommodate more than one flash type per board. - * - * Copyright 2005-2007 PMC-Sierra, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#include <asm/io.h> - -#include <msp_prom.h> -#include <msp_regs.h> - - -static struct mtd_info **msp_flash; -static struct mtd_partition **msp_parts; -static struct map_info *msp_maps; -static int fcnt; - -#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n", __func__, __LINE__) - -static int __init init_msp_flash(void) -{ - int i, j, ret = -ENOMEM; - int offset, coff; - char *env; - int pcnt; - char flash_name[] = "flash0"; - char part_name[] = "flash0_0"; - unsigned addr, size; - - /* If ELB is disabled by "ful-mux" mode, we can't get at flash */ - if ((*DEV_ID_REG & DEV_ID_SINGLE_PC) && - (*ELB_1PC_EN_REG & SINGLE_PCCARD)) { - printk(KERN_NOTICE "Single PC Card mode: no flash access\n"); - return -ENXIO; - } - - /* examine the prom environment for flash devices */ - for (fcnt = 0; (env = prom_getenv(flash_name)); fcnt++) - flash_name[5] = '0' + fcnt + 1; - - if (fcnt < 1) - return -ENXIO; - - printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt); - - msp_flash = kcalloc(fcnt, sizeof(*msp_flash), GFP_KERNEL); - if (!msp_flash) - return -ENOMEM; - - msp_parts = kcalloc(fcnt, sizeof(*msp_parts), GFP_KERNEL); - if (!msp_parts) - goto free_msp_flash; - - msp_maps = kcalloc(fcnt, sizeof(*msp_maps), GFP_KERNEL); - if (!msp_maps) - goto free_msp_parts; - - /* loop over the flash devices, initializing each */ - for (i = 0; i < fcnt; i++) { - /* examine the prom environment for flash partititions */ - part_name[5] = '0' + i; - part_name[7] = '0'; - for (pcnt = 0; (env = prom_getenv(part_name)); pcnt++) - part_name[7] = '0' + pcnt + 1; - - if (pcnt == 0) { - printk(KERN_NOTICE "Skipping flash device %d " - "(no partitions defined)\n", i); - continue; - } - - msp_parts[i] = kcalloc(pcnt, sizeof(struct mtd_partition), - GFP_KERNEL); - if (!msp_parts[i]) - goto cleanup_loop; - - /* now initialize the devices proper */ - flash_name[5] = '0' + i; - env = prom_getenv(flash_name); - - if (sscanf(env, "%x:%x", &addr, &size) < 2) { - ret = -ENXIO; - kfree(msp_parts[i]); - goto cleanup_loop; - } - addr = CPHYSADDR(addr); - - printk(KERN_NOTICE - "MSP flash device \"%s\": 0x%08x at 0x%08x\n", - flash_name, size, addr); - /* This must matchs the actual size of the flash chip */ - msp_maps[i].size = size; - msp_maps[i].phys = addr; - - /* - * Platforms have a specific limit of the size of memory - * which may be mapped for flash: - */ - if (size > CONFIG_MSP_FLASH_MAP_LIMIT) - size = CONFIG_MSP_FLASH_MAP_LIMIT; - - msp_maps[i].virt = ioremap(addr, size); - if (msp_maps[i].virt == NULL) { - ret = -ENXIO; - kfree(msp_parts[i]); - goto cleanup_loop; - } - - msp_maps[i].bankwidth = 1; - msp_maps[i].name = kstrndup(flash_name, 7, GFP_KERNEL); - if (!msp_maps[i].name) { - iounmap(msp_maps[i].virt); - kfree(msp_parts[i]); - goto cleanup_loop; - } - - for (j = 0; j < pcnt; j++) { - part_name[5] = '0' + i; - part_name[7] = '0' + j; - - env = prom_getenv(part_name); - - if (sscanf(env, "%x:%x:%n", &offset, &size, - &coff) < 2) { - ret = -ENXIO; - kfree(msp_maps[i].name); - iounmap(msp_maps[i].virt); - kfree(msp_parts[i]); - goto cleanup_loop; - } - - msp_parts[i][j].size = size; - msp_parts[i][j].offset = offset; - msp_parts[i][j].name = env + coff; - } - - /* now probe and add the device */ - simple_map_init(&msp_maps[i]); - msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]); - if (msp_flash[i]) { - msp_flash[i]->owner = THIS_MODULE; - mtd_device_register(msp_flash[i], msp_parts[i], pcnt); - } else { - printk(KERN_ERR "map probe failed for flash\n"); - ret = -ENXIO; - kfree(msp_maps[i].name); - iounmap(msp_maps[i].virt); - kfree(msp_parts[i]); - goto cleanup_loop; - } - } - - return 0; - -cleanup_loop: - while (i--) { - mtd_device_unregister(msp_flash[i]); - map_destroy(msp_flash[i]); - kfree(msp_maps[i].name); - iounmap(msp_maps[i].virt); - kfree(msp_parts[i]); - } - kfree(msp_maps); -free_msp_parts: - kfree(msp_parts); -free_msp_flash: - kfree(msp_flash); - return ret; -} - -static void __exit cleanup_msp_flash(void) -{ - int i; - - for (i = 0; i < fcnt; i++) { - mtd_device_unregister(msp_flash[i]); - map_destroy(msp_flash[i]); - iounmap((void *)msp_maps[i].virt); - - /* free the memory */ - kfree(msp_maps[i].name); - kfree(msp_parts[i]); - } - - kfree(msp_flash); - kfree(msp_parts); - kfree(msp_maps); -} - -MODULE_AUTHOR("PMC-Sierra, Inc"); -MODULE_DESCRIPTION("MTD map driver for PMC-Sierra MSP boards"); -MODULE_LICENSE("GPL"); - -module_init(init_msp_flash); -module_exit(cleanup_msp_flash); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 44bea3f65060..b8ae1ec14e17 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -23,7 +23,6 @@ #include "mtdcore.h" static LIST_HEAD(blktrans_majors); -static DEFINE_MUTEX(blktrans_ref_mutex); static void blktrans_dev_release(struct kref *kref) { @@ -37,26 +36,9 @@ static void blktrans_dev_release(struct kref *kref) kfree(dev); } -static struct mtd_blktrans_dev *blktrans_dev_get(struct gendisk *disk) -{ - struct mtd_blktrans_dev *dev; - - mutex_lock(&blktrans_ref_mutex); - dev = disk->private_data; - - if (!dev) - goto unlock; - kref_get(&dev->ref); -unlock: - mutex_unlock(&blktrans_ref_mutex); - return dev; -} - static void blktrans_dev_put(struct mtd_blktrans_dev *dev) { - mutex_lock(&blktrans_ref_mutex); kref_put(&dev->ref, blktrans_dev_release); - mutex_unlock(&blktrans_ref_mutex); } @@ -201,19 +183,16 @@ static blk_status_t mtd_queue_rq(struct blk_mq_hw_ctx *hctx, static int blktrans_open(struct block_device *bdev, fmode_t mode) { - struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); + struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; int ret = 0; - if (!dev) - return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ + kref_get(&dev->ref); - mutex_lock(&mtd_table_mutex); mutex_lock(&dev->lock); if (dev->open) goto unlock; - kref_get(&dev->ref); __module_get(dev->tr->owner); if (!dev->mtd) @@ -233,8 +212,6 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) unlock: dev->open++; mutex_unlock(&dev->lock); - mutex_unlock(&mtd_table_mutex); - blktrans_dev_put(dev); return ret; error_release: @@ -242,27 +219,20 @@ error_release: dev->tr->release(dev); error_put: module_put(dev->tr->owner); - kref_put(&dev->ref, blktrans_dev_release); mutex_unlock(&dev->lock); - mutex_unlock(&mtd_table_mutex); blktrans_dev_put(dev); return ret; } static void blktrans_release(struct gendisk *disk, fmode_t mode) { - struct mtd_blktrans_dev *dev = blktrans_dev_get(disk); - - if (!dev) - return; + struct mtd_blktrans_dev *dev = disk->private_data; - mutex_lock(&mtd_table_mutex); mutex_lock(&dev->lock); if (--dev->open) goto unlock; - kref_put(&dev->ref, blktrans_dev_release); module_put(dev->tr->owner); if (dev->mtd) { @@ -272,18 +242,14 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode) } unlock: mutex_unlock(&dev->lock); - mutex_unlock(&mtd_table_mutex); blktrans_dev_put(dev); } static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); + struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; int ret = -ENXIO; - if (!dev) - return ret; - mutex_lock(&dev->lock); if (!dev->mtd) @@ -292,7 +258,6 @@ static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) ret = dev->tr->getgeo ? dev->tr->getgeo(dev, geo) : -ENOTTY; unlock: mutex_unlock(&dev->lock); - blktrans_dev_put(dev); return ret; } @@ -315,12 +280,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) struct gendisk *gd; int ret; - if (mutex_trylock(&mtd_table_mutex)) { - mutex_unlock(&mtd_table_mutex); - BUG(); - } + lockdep_assert_held(&mtd_table_mutex); - mutex_lock(&blktrans_ref_mutex); list_for_each_entry(d, &tr->devs, list) { if (new->devnum == -1) { /* Use first free number */ @@ -332,7 +293,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) } } else if (d->devnum == new->devnum) { /* Required number taken */ - mutex_unlock(&blktrans_ref_mutex); return -EBUSY; } else if (d->devnum > new->devnum) { /* Required number was free */ @@ -350,14 +310,11 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) * minor numbers and that the disk naming code below can cope * with this number. */ if (new->devnum > (MINORMASK >> tr->part_bits) || - (tr->part_bits && new->devnum >= 27 * 26)) { - mutex_unlock(&blktrans_ref_mutex); + (tr->part_bits && new->devnum >= 27 * 26)) return ret; - } list_add_tail(&new->list, &tr->devs); added: - mutex_unlock(&blktrans_ref_mutex); mutex_init(&new->lock); kref_init(&new->ref); @@ -449,10 +406,7 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) { unsigned long flags; - if (mutex_trylock(&mtd_table_mutex)) { - mutex_unlock(&mtd_table_mutex); - BUG(); - } + lockdep_assert_held(&mtd_table_mutex); if (old->disk_attributes) sysfs_remove_group(&disk_to_dev(old->disk)->kobj, diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index a80809543793..03e3de3a5d79 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -322,6 +322,10 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) if (!(mtd->flags & MTD_WRITEABLE)) dev->mbd.readonly = 1; + if (mtd_type_is_nand(mtd)) + pr_warn("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n", + tr->name, mtd->name); + if (add_mtd_blktrans_dev(&dev->mbd)) kfree(dev); } diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index d92914f73d52..7c51952ce55d 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -46,6 +46,10 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) dev->tr = tr; dev->readonly = 1; + if (mtd_type_is_nand(mtd)) + pr_warn("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n", + tr->name, mtd->name); + if (add_mtd_blktrans_dev(dev)) kfree(dev); } diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 6e4d0017c0bd..f685a581df48 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -641,6 +641,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c int i; size_t size; struct mtd_concat *concat; + struct mtd_info *subdev_master = NULL; uint32_t max_erasesize, curr_erasesize; int num_erase_region; int max_writebufsize = 0; @@ -679,18 +680,24 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; - if (subdev[0]->_writev) + + subdev_master = mtd_get_master(subdev[0]); + if (subdev_master->_writev) concat->mtd._writev = concat_writev; - if (subdev[0]->_read_oob) + if (subdev_master->_read_oob) concat->mtd._read_oob = concat_read_oob; - if (subdev[0]->_write_oob) + if (subdev_master->_write_oob) concat->mtd._write_oob = concat_write_oob; - if (subdev[0]->_block_isbad) + if (subdev_master->_block_isbad) concat->mtd._block_isbad = concat_block_isbad; - if (subdev[0]->_block_markbad) + if (subdev_master->_block_markbad) concat->mtd._block_markbad = concat_block_markbad; - if (subdev[0]->_panic_write) + if (subdev_master->_panic_write) concat->mtd._panic_write = concat_panic_write; + if (subdev_master->_read) + concat->mtd._read = concat_read; + if (subdev_master->_write) + concat->mtd._write = concat_write; concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; @@ -721,14 +728,22 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c subdev[i]->flags & MTD_WRITEABLE; } + subdev_master = mtd_get_master(subdev[i]); concat->mtd.size += subdev[i]->size; concat->mtd.ecc_stats.badblocks += subdev[i]->ecc_stats.badblocks; if (concat->mtd.writesize != subdev[i]->writesize || concat->mtd.subpage_sft != subdev[i]->subpage_sft || concat->mtd.oobsize != subdev[i]->oobsize || - !concat->mtd._read_oob != !subdev[i]->_read_oob || - !concat->mtd._write_oob != !subdev[i]->_write_oob) { + !concat->mtd._read_oob != !subdev_master->_read_oob || + !concat->mtd._write_oob != !subdev_master->_write_oob) { + /* + * Check against subdev[i] for data members, because + * subdev's attributes may be different from master + * mtd device. Check against subdev's master mtd + * device for callbacks, because the existence of + * subdev's callbacks is decided by master mtd device. + */ kfree(concat); printk("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); @@ -744,8 +759,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.name = name; concat->mtd._erase = concat_erase; - concat->mtd._read = concat_read; - concat->mtd._write = concat_write; concat->mtd._sync = concat_sync; concat->mtd._lock = concat_lock; concat->mtd._unlock = concat_unlock; diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 630728de4b7c..67b7cb67c030 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -480,9 +480,9 @@ config MTD_NAND_RICOH select MTD_SM_COMMON help Enable support for Ricoh R5C852 xD card reader - You also need to enable ether + You also need to enable either NAND SSFDC (SmartMedia) read only translation layer' or new - expermental, readwrite + experimental, readwrite 'SmartMedia/xD new translation layer' config MTD_NAND_DISKONCHIP diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c index d0e8ffd55c22..9dbf031716a6 100644 --- a/drivers/mtd/nand/raw/cafe_nand.c +++ b/drivers/mtd/nand/raw/cafe_nand.c @@ -751,7 +751,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, "CAFE NAND", mtd); if (err) { dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq); - goto out_ior; + goto out_free_rs; } /* Disable master reset, enable NAND clock */ @@ -795,6 +795,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, /* Disable NAND IRQ in global IRQ mask register */ cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); free_irq(pdev->irq, mtd); + out_free_rs: + free_rs(cafe->rs); out_ior: pci_iounmap(pdev, cafe->mmio); out_free_mtd: diff --git a/drivers/mtd/nand/raw/intel-nand-controller.c b/drivers/mtd/nand/raw/intel-nand-controller.c index 8b49fd56cf96..29e8a546dcd6 100644 --- a/drivers/mtd/nand/raw/intel-nand-controller.c +++ b/drivers/mtd/nand/raw/intel-nand-controller.c @@ -631,19 +631,26 @@ static int ebu_nand_probe(struct platform_device *pdev) ebu_host->clk_rate = clk_get_rate(ebu_host->clk); ebu_host->dma_tx = dma_request_chan(dev, "tx"); - if (IS_ERR(ebu_host->dma_tx)) - return dev_err_probe(dev, PTR_ERR(ebu_host->dma_tx), - "failed to request DMA tx chan!.\n"); + if (IS_ERR(ebu_host->dma_tx)) { + ret = dev_err_probe(dev, PTR_ERR(ebu_host->dma_tx), + "failed to request DMA tx chan!.\n"); + goto err_disable_unprepare_clk; + } ebu_host->dma_rx = dma_request_chan(dev, "rx"); - if (IS_ERR(ebu_host->dma_rx)) - return dev_err_probe(dev, PTR_ERR(ebu_host->dma_rx), - "failed to request DMA rx chan!.\n"); + if (IS_ERR(ebu_host->dma_rx)) { + ret = dev_err_probe(dev, PTR_ERR(ebu_host->dma_rx), + "failed to request DMA rx chan!.\n"); + ebu_host->dma_rx = NULL; + goto err_cleanup_dma; + } resname = devm_kasprintf(dev, GFP_KERNEL, "addr_sel%d", cs); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resname); - if (!res) - return -EINVAL; + if (!res) { + ret = -EINVAL; + goto err_cleanup_dma; + } ebu_host->cs[cs].addr_sel = res->start; writel(ebu_host->cs[cs].addr_sel | EBU_ADDR_MASK(5) | EBU_ADDR_SEL_REGEN, ebu_host->ebu + EBU_ADDR_SEL(cs)); @@ -653,7 +660,8 @@ static int ebu_nand_probe(struct platform_device *pdev) mtd = nand_to_mtd(&ebu_host->chip); if (!mtd->name) { dev_err(ebu_host->dev, "NAND label property is mandatory\n"); - return -EINVAL; + ret = -EINVAL; + goto err_cleanup_dma; } mtd->dev.parent = dev; @@ -681,6 +689,7 @@ err_clean_nand: nand_cleanup(&ebu_host->chip); err_cleanup_dma: ebu_dma_cleanup(ebu_host); +err_disable_unprepare_clk: clk_disable_unprepare(ebu_host->clk); return ret; diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 817bddccb775..ac3be92872d0 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -580,7 +580,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, u32 *addrs = nfc->cmdfifo.rw.addrs; u32 cs = nfc->param.chip_select; u32 cmd0, cmd_num, row_start; - int ret = 0, i; + int i; cmd_num = sizeof(struct nand_rw_cmd) / sizeof(int); @@ -620,7 +620,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, meson_nfc_cmd_idle(nfc, nfc->timing.tadl); } - return ret; + return 0; } static int meson_nfc_write_page_sub(struct nand_chip *nand, diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index dced32a126d9..b7ad030225f8 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -447,6 +447,35 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, return 0; } +/* Check if a potential BBT block is marked as bad */ +static int bbt_block_checkbad(struct nand_chip *this, struct nand_bbt_descr *td, + loff_t offs, uint8_t *buf) +{ + struct nand_bbt_descr *bd = this->badblock_pattern; + + /* + * No need to check for a bad BBT block if the BBM area overlaps with + * the bad block table marker area in OOB since writing a BBM here + * invalidates the bad block table marker anyway. + */ + if (!(td->options & NAND_BBT_NO_OOB) && + td->offs >= bd->offs && td->offs < bd->offs + bd->len) + return 0; + + /* + * There is no point in checking for a bad block marker if writing + * such marker is not supported + */ + if (this->bbt_options & NAND_BBT_NO_OOB_BBM || + this->options & NAND_NO_BBM_QUIRK) + return 0; + + if (scan_block_fast(this, bd, offs, buf) > 0) + return 1; + + return 0; +} + /** * create_bbt - [GENERIC] Create a bad block table by scanning the device * @this: NAND chip object @@ -560,6 +589,10 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf, int actblock = startblock + dir * block; loff_t offs = (loff_t)actblock << this->bbt_erase_shift; + /* Check if block is marked bad */ + if (bbt_block_checkbad(this, td, offs, buf)) + continue; + /* Read first page */ scan_read(this, buf, offs, mtd->writesize, td); if (!check_pattern(buf, scanlen, mtd->writesize, td)) { diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index b1839eef5b65..b26d4947af02 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -911,7 +911,7 @@ static int omap_correct_data(struct nand_chip *chip, u_char *dat, } /** - * omap_calcuate_ecc - Generate non-inverted ECC bytes. + * omap_calculate_ecc - Generate non-inverted ECC bytes. * @chip: NAND chip object * @dat: The pointer to data on which ecc is computed * @ecc_code: The ecc_code buffer diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 446ba8d43fbc..2c8685f1f2fa 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -288,6 +288,8 @@ static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand, struct spinand_device *spinand = nand_to_spinand(nand); bool enable = (req->mode != MTD_OPS_RAW); + memset(spinand->oobbuf, 0xff, nanddev_per_page_oobsize(nand)); + /* Only enable or disable the engine */ return spinand_ecc_enable(spinand, enable); } @@ -307,7 +309,7 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand, if (req->type == NAND_PAGE_WRITE) return 0; - /* Finish a page write: check the status, report errors/bitflips */ + /* Finish a page read: check the status, report errors/bitflips */ ret = spinand_check_ecc_status(spinand, engine_conf->status); if (ret == -EBADMSG) mtd->ecc_stats.failed++; diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c index a9890350db02..3f31f1381a62 100644 --- a/drivers/mtd/nand/spi/macronix.c +++ b/drivers/mtd/nand/spi/macronix.c @@ -126,7 +126,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35LF4GE4AD", @@ -136,7 +136,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX35LF1G24AD", @@ -146,16 +146,16 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX35LF2G24AD", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24), - NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX35LF4G24AD", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35), @@ -164,7 +164,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX31LF1GE4BC", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e), @@ -173,7 +173,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0 /*SPINAND_HAS_QE_BIT*/, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), SPINAND_INFO("MX31UF1GE4BC", @@ -183,7 +183,7 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0 /*SPINAND_HAS_QE_BIT*/, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, mx35lf1ge4ab_ecc_get_status)), diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 6e0d5ce9b010..c546f8c5f24d 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -239,7 +239,7 @@ err: static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) { - struct partition *part = (struct partition*)dev; + struct partition *part = container_of(dev, struct partition, mbd); u_long addr; size_t retlen; int rc; @@ -600,7 +600,7 @@ static int find_free_sector(const struct partition *part, const struct block *bl static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, ulong *old_addr) { - struct partition *part = (struct partition*)dev; + struct partition *part = container_of(dev, struct partition, mbd); struct block *block; u_long addr; int i; @@ -666,7 +666,7 @@ err: static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) { - struct partition *part = (struct partition*)dev; + struct partition *part = container_of(dev, struct partition, mbd); u_long old_addr; int i; int rc = 0; @@ -705,9 +705,37 @@ err: return rc; } +static int rfd_ftl_discardsect(struct mtd_blktrans_dev *dev, + unsigned long sector, unsigned int nr_sects) +{ + struct partition *part = container_of(dev, struct partition, mbd); + u_long addr; + int rc; + + while (nr_sects) { + if (sector >= part->sector_count) + return -EIO; + + addr = part->sector_map[sector]; + + if (addr != -1) { + rc = mark_sector_deleted(part, addr); + if (rc) + return rc; + + part->sector_map[sector] = -1; + } + + sector++; + nr_sects--; + } + + return 0; +} + static int rfd_ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) { - struct partition *part = (struct partition*)dev; + struct partition *part = container_of(dev, struct partition, mbd); geo->heads = 1; geo->sectors = SECTORS_PER_TRACK; @@ -720,7 +748,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { struct partition *part; - if (mtd->type != MTD_NORFLASH || mtd->size > UINT_MAX) + if ((mtd->type != MTD_NORFLASH && mtd->type != MTD_RAM) || + mtd->size > UINT_MAX) return; part = kzalloc(sizeof(struct partition), GFP_KERNEL); @@ -754,7 +783,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) printk(KERN_INFO PREFIX "name: '%s' type: %d flags %x\n", mtd->name, mtd->type, mtd->flags); - if (!add_mtd_blktrans_dev((void*)part)) + if (!add_mtd_blktrans_dev(&part->mbd)) return; } out: @@ -763,7 +792,7 @@ out: static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev) { - struct partition *part = (struct partition*)dev; + struct partition *part = container_of(dev, struct partition, mbd); int i; for (i=0; i<part->total_blocks; i++) { @@ -771,10 +800,10 @@ static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev) part->mbd.mtd->name, i, part->blocks[i].erases); } - del_mtd_blktrans_dev(dev); vfree(part->sector_map); kfree(part->header_cache); kfree(part->blocks); + del_mtd_blktrans_dev(&part->mbd); } static struct mtd_blktrans_ops rfd_ftl_tr = { @@ -785,6 +814,7 @@ static struct mtd_blktrans_ops rfd_ftl_tr = { .readsect = rfd_ftl_readsect, .writesect = rfd_ftl_writesect, + .discard = rfd_ftl_discardsect, .getgeo = rfd_ftl_getgeo, .add_mtd = rfd_ftl_add_mtd, .remove_dev = rfd_ftl_remove_dev, |