Merge tag 'nand/for-5.15' into mtd/next
authorMiquel Raynal <miquel.raynal@bootlin.com>
Thu, 2 Sep 2021 22:04:16 +0000 (00:04 +0200)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Thu, 2 Sep 2021 22:04:16 +0000 (00:04 +0200)
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

12 files changed:
Documentation/devicetree/bindings/mtd/partitions/redboot-fis.txt [deleted file]
Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml [new file with mode: 0644]
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/rfd_ftl.c

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 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 6ce4bc5..12c1803 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);
@@ -448,10 +405,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 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,