Merge tag 'mtd/for-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 5 Sep 2021 17:50:12 +0000 (10:50 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 5 Sep 2021 17:50:12 +0000 (10:50 -0700)
Pull MTD updates from Miquel Raynal:
 "MTD changes:
   - blkdevs:
       - Simplify the refcounting in blktrans_{open, release}
       - Simplify blktrans_getgeo
       - Remove blktrans_ref_mutex
       - Simplify blktrans_dev_get
       - Use lockdep_assert_held
       - Don't hold del_mtd_blktrans_dev in blktrans_{open, release}
   - ftl:
       - Don't cast away the type when calling add_mtd_blktrans_dev
       - Don't cast away the type when calling add_mtd_blktrans_dev
       - Use container_of() rather than cast
       - Fix use-after-free
       - Add discard support
       - Allow use of MTD_RAM for testing purposes
   - concat:
       - Check _read, _write callbacks existence before assignment
       - Judge callback existence based on the master
   - maps:
       - Maps: remove dead MTD map driver for PMC-Sierra MSP boards
   - mtdblock:
       - Warn if added for a NAND device
       - Add comment about UBI block devices
       - Update old JFFS2 mention in Kconfig
   - partitions:
       - Redboot: convert to YAML

  NAND core changes:
   - Repair Miquel Raynal's email address in MAINTAINERS
   - Fix a couple of spelling mistakes in Kconfig
   - bbt: Skip bad blocks when searching for the BBT in NAND
   - Remove never changed ret variable

  Raw NAND changes:
   - cafe: Fix a resource leak in the error handling path of 'cafe_nand_probe()'
   - intel: Fix error handling in probe
   - omap: Fix kernel doc warning on 'calcuate' typo
   - gpmc: Fix the ECC bytes vs. OOB bytes equation

  SPI-NAND core changes:
   - Properly fill the OOB area.
   - Fix comment

  SPI-NAND drivers changes:
   - macronix: Add Quad support for serial NAND flash"

* tag 'mtd/for-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (30 commits)
  mtd: rawnand: cafe: Fix a resource leak in the error handling path of 'cafe_nand_probe()'
  mtd_blkdevs: simplify the refcounting in blktrans_{open, release}
  mtd_blkdevs: simplify blktrans_getgeo
  mtd_blkdevs: remove blktrans_ref_mutex
  mtd_blkdevs: simplify blktrans_dev_get
  mtd/rfd_ftl: don't cast away the type when calling add_mtd_blktrans_dev
  mtd/ftl: don't cast away the type when calling add_mtd_blktrans_dev
  mtd_blkdevs: use lockdep_assert_held
  mtd_blkdevs: don't hold del_mtd_blktrans_dev in blktrans_{open, release}
  mtd: rawnand: intel: Fix error handling in probe
  mtd: mtdconcat: Check _read, _write callbacks existence before assignment
  mtd: mtdconcat: Judge callback existence based on the master
  mtd: maps: remove dead MTD map driver for PMC-Sierra MSP boards
  mtd: rfd_ftl: use container_of() rather than cast
  mtd: rfd_ftl: fix use-after-free
  mtd: rfd_ftl: add discard support
  mtd: rfd_ftl: allow use of MTD_RAM for testing purposes
  mtdblock: Warn if added for a NAND device
  mtd: spinand: macronix: Add Quad support for serial NAND flash
  mtdblock: Add comment about UBI block devices
  ...

22 files changed:
Documentation/devicetree/bindings/mtd/gpmc-nand.txt
Documentation/devicetree/bindings/mtd/partitions/redboot-fis.txt [deleted file]
Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml [new file with mode: 0644]
MAINTAINERS
drivers/mtd/Kconfig
drivers/mtd/ftl.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/pmcmsp-flash.c [deleted file]
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdblock.c
drivers/mtd/mtdblock_ro.c
drivers/mtd/mtdconcat.c
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/cafe_nand.c
drivers/mtd/nand/raw/intel-nand-controller.c
drivers/mtd/nand/raw/meson_nand.c
drivers/mtd/nand/raw/nand_bbt.c
drivers/mtd/nand/raw/omap2.c
drivers/mtd/nand/spi/core.c
drivers/mtd/nand/spi/macronix.c
drivers/mtd/rfd_ftl.c

index 44919d4..c459f16 100644 (file)
@@ -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 (file)
index fd0ebe4..0000000
+++ /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 (file)
index 0000000..fee8d81
--- /dev/null
@@ -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>;
+      };
+    };
index e4bdea0..cfec5dc 100644 (file)
@@ -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
index 8bab6f8..796a2ec 100644 (file)
@@ -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
index 9b33c08..f655d29 100644 (file)
@@ -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;
        }
 
index 6650acb..aaa164b 100644 (file)
@@ -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
index 79f018c..11fea9c 100644 (file)
@@ -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 (file)
index 2051f28..0000000
+++ /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);
index 44bea3f..b8ae1ec 100644 (file)
@@ -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,
index a808095..03e3de3 100644 (file)
@@ -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);
 }
index d92914f..7c51952 100644 (file)
@@ -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);
 }
index 6e4d001..f685a58 100644 (file)
@@ -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;
index 630728d..67b7cb6 100644 (file)
@@ -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
index d0e8ffd..9dbf031 100644 (file)
@@ -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:
index 8b49fd5..29e8a54 100644 (file)
@@ -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;
index 817bddc..ac3be92 100644 (file)
@@ -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,
index dced32a..b7ad030 100644 (file)
@@ -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)) {
index b1839ee..b26d494 100644 (file)
@@ -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
index 446ba8d..2c8685f 100644 (file)
@@ -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++;
index a989035..3f31f13 100644 (file)
@@ -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)),
 
index 6e0d5ce..c546f8c 100644 (file)
@@ -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,