Commit 6b6dc4f4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mtd/for-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux

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
  ...
parents 0319b848 c1fe77e4
...@@ -122,7 +122,7 @@ on various other factors also like; ...@@ -122,7 +122,7 @@ on various other factors also like;
so the device should have enough free bytes available its OOB/Spare so the device should have enough free bytes available its OOB/Spare
area to accommodate ECC for entire page. In general following expression area to accommodate ECC for entire page. In general following expression
helps in determining if given device can accommodate ECC syndrome: helps in determining if given device can accommodate ECC syndrome:
"2 + (PAGESIZE / 512) * ECC_BYTES" >= OOBSIZE" "2 + (PAGESIZE / 512) * ECC_BYTES" <= OOBSIZE"
where where
OOBSIZE number of bytes in OOB/spare area OOBSIZE number of bytes in OOB/spare area
PAGESIZE number of bytes in main-area of device page PAGESIZE number of bytes in main-area of device page
......
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>;
};
};
# 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>;
};
};
...@@ -1496,7 +1496,7 @@ F: drivers/amba/ ...@@ -1496,7 +1496,7 @@ F: drivers/amba/
F: include/linux/amba/bus.h F: include/linux/amba/bus.h
ARM PRIMECELL PL35X NAND CONTROLLER DRIVER 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> M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
S: Maintained S: Maintained
...@@ -1504,7 +1504,7 @@ F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml ...@@ -1504,7 +1504,7 @@ F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml
F: drivers/mtd/nand/raw/pl35x-nand-controller.c F: drivers/mtd/nand/raw/pl35x-nand-controller.c
ARM PRIMECELL PL35X SMC DRIVER 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> M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained S: Maintained
......
...@@ -45,10 +45,9 @@ config MTD_BLOCK ...@@ -45,10 +45,9 @@ config MTD_BLOCK
on RAM chips in this manner. This block device is a user of MTD on RAM chips in this manner. This block device is a user of MTD
devices performing that function. devices performing that function.
At the moment, it is also required for the Journalling Flash File Note that mounting a JFFS2 filesystem doesn't require using mtdblock.
System(s) to obtain a handle on the MTD device when it's mounted It's possible to mount a rootfs using the MTD device on the "root="
(although JFFS and JFFS2 don't actually use any of the functionality bootargs as "root=mtd2" or "root=mtd:name_of_device".
of the mtdblock device).
Later, it may be extended to perform read/erase/modify/write cycles Later, it may be extended to perform read/erase/modify/write cycles
on flash chips to emulate a smaller block size. Needless to say, on flash chips to emulate a smaller block size. Needless to say,
...@@ -70,6 +69,9 @@ config MTD_BLOCK_RO ...@@ -70,6 +69,9 @@ config MTD_BLOCK_RO
You do not need this option for use with the DiskOnChip devices. For You do not need this option for use with the DiskOnChip devices. For
those, enable NFTL support (CONFIG_NFTL) instead. 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 config FTL
tristate "FTL (Flash Translation Layer) support" tristate "FTL (Flash Translation Layer) support"
depends on BLOCK depends on BLOCK
......
...@@ -1029,7 +1029,7 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -1029,7 +1029,7 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
partition->mbd.tr = tr; partition->mbd.tr = tr;
partition->mbd.devnum = -1; partition->mbd.devnum = -1;
if (!add_mtd_blktrans_dev((void *)partition)) if (!add_mtd_blktrans_dev(&partition->mbd))
return; return;
} }
......
...@@ -127,29 +127,6 @@ config MTD_PHYSMAP_GPIO_ADDR ...@@ -127,29 +127,6 @@ config MTD_PHYSMAP_GPIO_ADDR
Extend the physmap driver to allow flashes to be partially Extend the physmap driver to allow flashes to be partially
physically addressed and assisted by GPIOs. 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 config MTD_SUN_UFLASH
tristate "Sun Microsystems userflash support" tristate "Sun Microsystems userflash support"
depends on SPARC && MTD_CFI && PCI depends on SPARC && MTD_CFI && PCI
......
...@@ -25,7 +25,6 @@ physmap-objs-$(CONFIG_MTD_PHYSMAP_IXP4XX) += physmap-ixp4xx.o ...@@ -25,7 +25,6 @@ physmap-objs-$(CONFIG_MTD_PHYSMAP_IXP4XX) += physmap-ixp4xx.o
physmap-objs := $(physmap-objs-y) physmap-objs := $(physmap-objs-y)
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
obj-$(CONFIG_MTD_PISMO) += pismo.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_PCMCIA) += pcmciamtd.o
obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
......
/*
* 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);
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include "mtdcore.h" #include "mtdcore.h"
static LIST_HEAD(blktrans_majors); static LIST_HEAD(blktrans_majors);
static DEFINE_MUTEX(blktrans_ref_mutex);
static void blktrans_dev_release(struct kref *kref) static void blktrans_dev_release(struct kref *kref)
{ {
...@@ -37,26 +36,9 @@ static void blktrans_dev_release(struct kref *kref) ...@@ -37,26 +36,9 @@ static void blktrans_dev_release(struct kref *kref)
kfree(dev); 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) static void blktrans_dev_put(struct mtd_blktrans_dev *dev)
{ {
mutex_lock(&blktrans_ref_mutex);
kref_put(&dev->ref, blktrans_dev_release); 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, ...@@ -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) 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; int ret = 0;
if (!dev) kref_get(&dev->ref);
return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/
mutex_lock(&mtd_table_mutex);
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
if (dev->open) if (dev->open)
goto unlock; goto unlock;
kref_get(&dev->ref);
__module_get(dev->tr->owner); __module_get(dev->tr->owner);
if (!dev->mtd) if (!dev->mtd)
...@@ -233,8 +212,6 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) ...@@ -233,8 +212,6 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
unlock: unlock:
dev->open++; dev->open++;
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
mutex_unlock(&mtd_table_mutex);
blktrans_dev_put(dev);
return ret; return ret;
error_release: error_release:
...@@ -242,27 +219,20 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) ...@@ -242,27 +219,20 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
dev->tr->release(dev); dev->tr->release(dev);
error_put: error_put:
module_put(dev->tr->owner); module_put(dev->tr->owner);
kref_put(&dev->ref, blktrans_dev_release);
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
mutex_unlock(&mtd_table_mutex);
blktrans_dev_put(dev); blktrans_dev_put(dev);
return ret; return ret;
} }
static void blktrans_release(struct gendisk *disk, fmode_t mode) static void blktrans_release(struct gendisk *disk, fmode_t mode)
{ {
struct mtd_blktrans_dev *dev = blktrans_dev_get(disk); struct mtd_blktrans_dev *dev = disk->private_data;
if (!dev)
return;
mutex_lock(&mtd_table_mutex);
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
if (--dev->open) if (--dev->open)
goto unlock; goto unlock;
kref_put(&dev->ref, blktrans_dev_release);
module_put(dev->tr->owner); module_put(dev->tr->owner);
if (dev->mtd) { if (dev->mtd) {
...@@ -272,18 +242,14 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode) ...@@ -272,18 +242,14 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode)
} }
unlock: unlock:
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
mutex_unlock(&mtd_table_mutex);
blktrans_dev_put(dev); blktrans_dev_put(dev);
} }
static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) 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; int ret = -ENXIO;
if (!dev)
return ret;
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
if (!dev->mtd) if (!dev->mtd)
...@@ -292,7 +258,6 @@ static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) ...@@ -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; ret = dev->tr->getgeo ? dev->tr->getgeo(dev, geo) : -ENOTTY;
unlock: unlock:
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
blktrans_dev_put(dev);
return ret; return ret;
} }
...@@ -315,12 +280,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) ...@@ -315,12 +280,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
struct gendisk *gd; struct gendisk *gd;
int ret; int ret;
if (mutex_trylock(&mtd_table_mutex)) { lockdep_assert_held(&mtd_table_mutex);
mutex_unlock(&mtd_table_mutex);
BUG();
}
mutex_lock(&blktrans_ref_mutex);
list_for_each_entry(d, &tr->devs, list) { list_for_each_entry(d, &tr->devs, list) {
if (new->devnum == -1) { if (new->devnum == -1) {
/* Use first free number */ /* Use first free number */
...@@ -332,7 +293,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) ...@@ -332,7 +293,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
} }
} else if (d->devnum == new->devnum) { } else if (d->devnum == new->devnum) {
/* Required number taken */ /* Required number taken */
mutex_unlock(&blktrans_ref_mutex);
return -EBUSY; return -EBUSY;
} else if (d->devnum > new->devnum) { } else if (d->devnum > new->devnum) {
/* Required number was free */ /* Required number was free */
...@@ -350,14 +310,11 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) ...@@ -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 * minor numbers and that the disk naming code below can cope
* with this number. */ * with this number. */
if (new->devnum > (MINORMASK >> tr->part_bits) || if (new->devnum > (MINORMASK >> tr->part_bits) ||
(tr->part_bits && new->devnum >= 27 * 26)) { (tr->part_bits && new->devnum >= 27 * 26))
mutex_unlock(&blktrans_ref_mutex);
return ret; return ret;
}
list_add_tail(&new->list, &tr->devs); list_add_tail(&new->list, &tr->devs);
added: added:
mutex_unlock(&blktrans_ref_mutex);
mutex_init(&new->lock); mutex_init(&new->lock);
kref_init(&new->ref); kref_init(&new->ref);
...@@ -449,10 +406,7 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) ...@@ -449,10 +406,7 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
{ {
unsigned long flags; unsigned long flags;
if (mutex_trylock(&mtd_table_mutex)) { lockdep_assert_held(&mtd_table_mutex);
mutex_unlock(&mtd_table_mutex);
BUG();
}
if (old->disk_attributes) if (old->disk_attributes)
sysfs_remove_group(&disk_to_dev(old->disk)->kobj, sysfs_remove_group(&disk_to_dev(old->disk)->kobj,
......
...@@ -322,6 +322,10 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -322,6 +322,10 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
if (!(mtd->flags & MTD_WRITEABLE)) if (!(mtd->flags & MTD_WRITEABLE))
dev->mbd.readonly = 1; 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)) if (add_mtd_blktrans_dev(&dev->mbd))
kfree(dev); kfree(dev);
} }
......
...@@ -46,6 +46,10 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -46,6 +46,10 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
dev->tr = tr; dev->tr = tr;
dev->readonly = 1; 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)) if (add_mtd_blktrans_dev(dev))
kfree(dev); kfree(dev);
} }
......
...@@ -641,6 +641,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c ...@@ -641,6 +641,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
int i; int i;
size_t size; size_t size;
struct mtd_concat *concat; struct mtd_concat *concat;
struct mtd_info *subdev_master = NULL;
uint32_t max_erasesize, curr_erasesize; uint32_t max_erasesize, curr_erasesize;
int num_erase_region; int num_erase_region;
int max_writebufsize = 0; int max_writebufsize = 0;
...@@ -679,18 +680,24 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c ...@@ -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.subpage_sft = subdev[0]->subpage_sft;
concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.oobavail = subdev[0]->oobavail; 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; concat->mtd._writev = concat_writev;
if (subdev[0]->_read_oob) if (subdev_master->_read_oob)
concat->mtd._read_oob = concat_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; concat->mtd._write_oob = concat_write_oob;
if (subdev[0]->_block_isbad) if (subdev_master->_block_isbad)
concat->mtd._block_isbad = concat_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; concat->mtd._block_markbad = concat_block_markbad;
if (subdev[0]->_panic_write) if (subdev_master->_panic_write)
concat->mtd._panic_write = concat_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; 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 ...@@ -721,14 +728,22 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
subdev[i]->flags & MTD_WRITEABLE; subdev[i]->flags & MTD_WRITEABLE;
} }
subdev_master = mtd_get_master(subdev[i]);
concat->mtd.size += subdev[i]->size; concat->mtd.size += subdev[i]->size;
concat->mtd.ecc_stats.badblocks += concat->mtd.ecc_stats.badblocks +=
subdev[i]->ecc_stats.badblocks; subdev[i]->ecc_stats.badblocks;
if (concat->mtd.writesize != subdev[i]->writesize || if (concat->mtd.writesize != subdev[i]->writesize ||
concat->mtd.subpage_sft != subdev[i]->subpage_sft || concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
concat->mtd.oobsize != subdev[i]->oobsize || concat->mtd.oobsize != subdev[i]->oobsize ||
!concat->mtd._read_oob != !subdev[i]->_read_oob || !concat->mtd._read_oob != !subdev_master->_read_oob ||
!concat->mtd._write_oob != !subdev[i]->_write_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); kfree(concat);
printk("Incompatible OOB or ECC data on \"%s\"\n", printk("Incompatible OOB or ECC data on \"%s\"\n",
subdev[i]->name); subdev[i]->name);
...@@ -744,8 +759,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c ...@@ -744,8 +759,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.name = name; concat->mtd.name = name;
concat->mtd._erase = concat_erase; concat->mtd._erase = concat_erase;
concat->mtd._read = concat_read;
concat->mtd._write = concat_write;
concat->mtd._sync = concat_sync; concat->mtd._sync = concat_sync;
concat->mtd._lock = concat_lock; concat->mtd._lock = concat_lock;
concat->mtd._unlock = concat_unlock; concat->mtd._unlock = concat_unlock;
......
...@@ -480,9 +480,9 @@ config MTD_NAND_RICOH ...@@ -480,9 +480,9 @@ config MTD_NAND_RICOH
select MTD_SM_COMMON select MTD_SM_COMMON
help help
Enable support for Ricoh R5C852 xD card reader 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 NAND SSFDC (SmartMedia) read only translation layer' or new
expermental, readwrite experimental, readwrite
'SmartMedia/xD new translation layer' 'SmartMedia/xD new translation layer'
config MTD_NAND_DISKONCHIP config MTD_NAND_DISKONCHIP
......
...@@ -751,7 +751,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -751,7 +751,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
"CAFE NAND", mtd); "CAFE NAND", mtd);
if (err) { if (err) {
dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq); 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 */ /* Disable master reset, enable NAND clock */
...@@ -795,6 +795,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -795,6 +795,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
/* Disable NAND IRQ in global IRQ mask register */ /* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
free_irq(pdev->irq, mtd); free_irq(pdev->irq, mtd);
out_free_rs:
free_rs(cafe->rs);
out_ior: out_ior:
pci_iounmap(pdev, cafe->mmio); pci_iounmap(pdev, cafe->mmio);
out_free_mtd: out_free_mtd:
......
...@@ -631,19 +631,26 @@ static int ebu_nand_probe(struct platform_device *pdev) ...@@ -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->clk_rate = clk_get_rate(ebu_host->clk);
ebu_host->dma_tx = dma_request_chan(dev, "tx"); ebu_host->dma_tx = dma_request_chan(dev, "tx");
if (IS_ERR(ebu_host->dma_tx)) if (IS_ERR(ebu_host->dma_tx)) {
return dev_err_probe(dev, PTR_ERR(ebu_host->dma_tx), ret = dev_err_probe(dev, PTR_ERR(ebu_host->dma_tx),
"failed to request DMA tx chan!.\n"); "failed to request DMA tx chan!.\n");
goto err_disable_unprepare_clk;
}
ebu_host->dma_rx = dma_request_chan(dev, "rx"); ebu_host->dma_rx = dma_request_chan(dev, "rx");
if (IS_ERR(ebu_host->dma_rx)) if (IS_ERR(ebu_host->dma_rx)) {
return dev_err_probe(dev, PTR_ERR(ebu_host->dma_rx), ret = dev_err_probe(dev, PTR_ERR(ebu_host->dma_rx),
"failed to request DMA rx chan!.\n"); "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); resname = devm_kasprintf(dev, GFP_KERNEL, "addr_sel%d", cs);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resname); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resname);
if (!res) if (!res) {
return -EINVAL; ret = -EINVAL;
goto err_cleanup_dma;
}
ebu_host->cs[cs].addr_sel = res->start; ebu_host->cs[cs].addr_sel = res->start;
writel(ebu_host->cs[cs].addr_sel | EBU_ADDR_MASK(5) | EBU_ADDR_SEL_REGEN, writel(ebu_host->cs[cs].addr_sel | EBU_ADDR_MASK(5) | EBU_ADDR_SEL_REGEN,
ebu_host->ebu + EBU_ADDR_SEL(cs)); ebu_host->ebu + EBU_ADDR_SEL(cs));
...@@ -653,7 +660,8 @@ static int ebu_nand_probe(struct platform_device *pdev) ...@@ -653,7 +660,8 @@ static int ebu_nand_probe(struct platform_device *pdev)
mtd = nand_to_mtd(&ebu_host->chip); mtd = nand_to_mtd(&ebu_host->chip);
if (!mtd->name) { if (!mtd->name) {
dev_err(ebu_host->dev, "NAND label property is mandatory\n"); dev_err(ebu_host->dev, "NAND label property is mandatory\n");
return -EINVAL; ret = -EINVAL;
goto err_cleanup_dma;
} }
mtd->dev.parent = dev; mtd->dev.parent = dev;
...@@ -681,6 +689,7 @@ static int ebu_nand_probe(struct platform_device *pdev) ...@@ -681,6 +689,7 @@ static int ebu_nand_probe(struct platform_device *pdev)
nand_cleanup(&ebu_host->chip); nand_cleanup(&ebu_host->chip);
err_cleanup_dma: err_cleanup_dma:
ebu_dma_cleanup(ebu_host); ebu_dma_cleanup(ebu_host);
err_disable_unprepare_clk:
clk_disable_unprepare(ebu_host->clk); clk_disable_unprepare(ebu_host->clk);
return ret; return ret;
......
...@@ -580,7 +580,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, ...@@ -580,7 +580,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
u32 *addrs = nfc->cmdfifo.rw.addrs; u32 *addrs = nfc->cmdfifo.rw.addrs;
u32 cs = nfc->param.chip_select; u32 cs = nfc->param.chip_select;
u32 cmd0, cmd_num, row_start; u32 cmd0, cmd_num, row_start;
int ret = 0, i; int i;
cmd_num = sizeof(struct nand_rw_cmd) / sizeof(int); 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, ...@@ -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); meson_nfc_cmd_idle(nfc, nfc->timing.tadl);
} }
return ret; return 0;
} }
static int meson_nfc_write_page_sub(struct nand_chip *nand, static int meson_nfc_write_page_sub(struct nand_chip *nand,
......
...@@ -447,6 +447,35 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, ...@@ -447,6 +447,35 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
return 0; 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 * create_bbt - [GENERIC] Create a bad block table by scanning the device
* @this: NAND chip object * @this: NAND chip object
...@@ -560,6 +589,10 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf, ...@@ -560,6 +589,10 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf,
int actblock = startblock + dir * block; int actblock = startblock + dir * block;
loff_t offs = (loff_t)actblock << this->bbt_erase_shift; 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 */ /* Read first page */
scan_read(this, buf, offs, mtd->writesize, td); scan_read(this, buf, offs, mtd->writesize, td);
if (!check_pattern(buf, scanlen, mtd->writesize, td)) { if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
......
...@@ -911,7 +911,7 @@ static int omap_correct_data(struct nand_chip *chip, u_char *dat, ...@@ -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 * @chip: NAND chip object
* @dat: The pointer to data on which ecc is computed * @dat: The pointer to data on which ecc is computed
* @ecc_code: The ecc_code buffer * @ecc_code: The ecc_code buffer
......
...@@ -288,6 +288,8 @@ static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand, ...@@ -288,6 +288,8 @@ static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand,
struct spinand_device *spinand = nand_to_spinand(nand); struct spinand_device *spinand = nand_to_spinand(nand);
bool enable = (req->mode != MTD_OPS_RAW); bool enable = (req->mode != MTD_OPS_RAW);
memset(spinand->oobbuf, 0xff, nanddev_per_page_oobsize(nand));
/* Only enable or disable the engine */ /* Only enable or disable the engine */
return spinand_ecc_enable(spinand, enable); return spinand_ecc_enable(spinand, enable);
} }
...@@ -307,7 +309,7 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand, ...@@ -307,7 +309,7 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand,
if (req->type == NAND_PAGE_WRITE) if (req->type == NAND_PAGE_WRITE)
return 0; 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); ret = spinand_check_ecc_status(spinand, engine_conf->status);
if (ret == -EBADMSG) if (ret == -EBADMSG)
mtd->ecc_stats.failed++; mtd->ecc_stats.failed++;
......
...@@ -126,7 +126,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -126,7 +126,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)), mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35LF4GE4AD", SPINAND_INFO("MX35LF4GE4AD",
...@@ -136,7 +136,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -136,7 +136,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)), mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35LF1G24AD", SPINAND_INFO("MX35LF1G24AD",
...@@ -146,16 +146,16 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -146,16 +146,16 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
SPINAND_INFO("MX35LF2G24AD", SPINAND_INFO("MX35LF2G24AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24), 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), NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
SPINAND_INFO("MX35LF4G24AD", SPINAND_INFO("MX35LF4G24AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35), SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
...@@ -164,7 +164,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -164,7 +164,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
SPINAND_INFO("MX31LF1GE4BC", SPINAND_INFO("MX31LF1GE4BC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e), SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
...@@ -173,7 +173,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -173,7 +173,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0 /*SPINAND_HAS_QE_BIT*/, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)), mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX31UF1GE4BC", SPINAND_INFO("MX31UF1GE4BC",
...@@ -183,7 +183,7 @@ static const struct spinand_info macronix_spinand_table[] = { ...@@ -183,7 +183,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
0 /*SPINAND_HAS_QE_BIT*/, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)), mx35lf1ge4ab_ecc_get_status)),
......
...@@ -239,7 +239,7 @@ static int scan_header(struct partition *part) ...@@ -239,7 +239,7 @@ static int scan_header(struct partition *part)
static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) 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; u_long addr;
size_t retlen; size_t retlen;
int rc; int rc;
...@@ -600,7 +600,7 @@ static int find_free_sector(const struct partition *part, const struct block *bl ...@@ -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) 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; struct block *block;
u_long addr; u_long addr;
int i; int i;
...@@ -666,7 +666,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, ...@@ -666,7 +666,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) 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; u_long old_addr;
int i; int i;
int rc = 0; int rc = 0;
...@@ -705,9 +705,37 @@ static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char * ...@@ -705,9 +705,37 @@ static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *
return rc; 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) 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->heads = 1;
geo->sectors = SECTORS_PER_TRACK; geo->sectors = SECTORS_PER_TRACK;
...@@ -720,7 +748,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -720,7 +748,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{ {
struct partition *part; 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; return;
part = kzalloc(sizeof(struct partition), GFP_KERNEL); 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) ...@@ -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", printk(KERN_INFO PREFIX "name: '%s' type: %d flags %x\n",
mtd->name, mtd->type, mtd->flags); mtd->name, mtd->type, mtd->flags);
if (!add_mtd_blktrans_dev((void*)part)) if (!add_mtd_blktrans_dev(&part->mbd))
return; return;
} }
out: out:
...@@ -763,7 +792,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -763,7 +792,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev) 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; int i;
for (i=0; i<part->total_blocks; i++) { for (i=0; i<part->total_blocks; i++) {
...@@ -771,10 +800,10 @@ static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev) ...@@ -771,10 +800,10 @@ static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev)
part->mbd.mtd->name, i, part->blocks[i].erases); part->mbd.mtd->name, i, part->blocks[i].erases);
} }
del_mtd_blktrans_dev(dev);
vfree(part->sector_map); vfree(part->sector_map);
kfree(part->header_cache); kfree(part->header_cache);
kfree(part->blocks); kfree(part->blocks);
del_mtd_blktrans_dev(&part->mbd);
} }
static struct mtd_blktrans_ops rfd_ftl_tr = { static struct mtd_blktrans_ops rfd_ftl_tr = {
...@@ -785,6 +814,7 @@ static struct mtd_blktrans_ops rfd_ftl_tr = { ...@@ -785,6 +814,7 @@ static struct mtd_blktrans_ops rfd_ftl_tr = {
.readsect = rfd_ftl_readsect, .readsect = rfd_ftl_readsect,
.writesect = rfd_ftl_writesect, .writesect = rfd_ftl_writesect,
.discard = rfd_ftl_discardsect,
.getgeo = rfd_ftl_getgeo, .getgeo = rfd_ftl_getgeo,
.add_mtd = rfd_ftl_add_mtd, .add_mtd = rfd_ftl_add_mtd,
.remove_dev = rfd_ftl_remove_dev, .remove_dev = rfd_ftl_remove_dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment