diff options
42 files changed, 642 insertions, 320 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-mtd b/Documentation/ABI/testing/sysfs-class-mtd index 76ee192f80a0..3b5c3bca9186 100644 --- a/Documentation/ABI/testing/sysfs-class-mtd +++ b/Documentation/ABI/testing/sysfs-class-mtd @@ -222,3 +222,13 @@ Description: The number of blocks that are marked as reserved, if any, in this partition. These are typically used to store the in-flash bad block table (BBT). + +What: /sys/class/mtd/mtdX/offset +Date: March 2015 +KernelVersion: 4.1 +Contact: linux-mtd@lists.infradead.org +Description: + For a partition, the offset of that partition from the start + of the master device in bytes. This attribute is absent on + main devices, so it can be used to distinguish between + partitions and devices that aren't partitions. diff --git a/Documentation/devicetree/bindings/mtd/m25p80.txt b/Documentation/devicetree/bindings/mtd/m25p80.txt index 4611aa83531b..f20b111b502a 100644 --- a/Documentation/devicetree/bindings/mtd/m25p80.txt +++ b/Documentation/devicetree/bindings/mtd/m25p80.txt @@ -3,10 +3,13 @@ Required properties: - #address-cells, #size-cells : Must be present if the device has sub-nodes representing partitions. -- compatible : Should be the manufacturer and the name of the chip. Bear in mind - the DT binding is not Linux-only, but in case of Linux, see the - "spi_nor_ids" table in drivers/mtd/spi-nor/spi-nor.c for the list - of supported chips. +- compatible : May include a device-specific string consisting of the + manufacturer and name of the chip. Bear in mind the DT binding + is not Linux-only, but in case of Linux, see the "m25p_ids" + table in drivers/mtd/devices/m25p80.c for the list of supported + chips. + Must also include "nor-jedec" for any SPI NOR flash that can be + identified by the JEDEC READ ID opcode (0x9F). - reg : Chip-Select number - spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at @@ -22,7 +25,7 @@ Example: flash: m25p80@0 { #address-cells = <1>; #size-cells = <1>; - compatible = "spansion,m25p80"; + compatible = "spansion,m25p80", "nor-jedec"; reg = <0>; spi-max-frequency = <40000000>; m25p,fast-read; diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt index de8b517a5521..4f833e3c4f51 100644 --- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt @@ -14,7 +14,7 @@ Optional properties: - marvell,nand-enable-arbiter: Set to enable the bus arbiter - marvell,nand-keep-config: Set to keep the NAND controller config as set by the bootloader - - num-cs: Number of chipselect lines to usw + - num-cs: Number of chipselect lines to use - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false - nand-ecc-strength: number of bits to correct per ECC step diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt index 0273adb8638c..086d6f44c4b9 100644 --- a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt +++ b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt @@ -21,7 +21,7 @@ Optional properties: - nand-ecc-mode : one of the supported ECC modes ("hw", "hw_syndrome", "soft", "soft_bch" or "none") -see Documentation/devicetree/mtd/nand.txt for generic bindings. +see Documentation/devicetree/bindings/mtd/nand.txt for generic bindings. Examples: diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 71fea895ce38..a03ad2951c7b 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -309,6 +309,19 @@ config MTD_SWAP The driver provides wear leveling by storing erase counter into the OOB. +config MTD_PARTITIONED_MASTER + bool "Retain master device when partitioned" + default n + depends on MTD + help + For historical reasons, by default, either a master is present or + several partitions are present, but not both. The concern was that + data listed in multiple partitions was dangerous; however, SCSI does + this and it is frequently useful for applications. This config option + leaves the master in even if the device is partitioned. It also makes + the parent of the partition device be the master device, rather than + what lies behind the master. + source "drivers/mtd/chips/Kconfig" source "drivers/mtd/maps/Kconfig" diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 423666b51efb..9a1a6ffd16b8 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -206,23 +206,23 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; } offset += (ersize * ernum); - } + } - if (offset != devsize) { - /* Argh */ - printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); - kfree(mtd->eraseregions); - kfree(cfi->cmdset_priv); - kfree(mtd); - return NULL; - } + if (offset != devsize) { + /* Argh */ + printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); + kfree(mtd->eraseregions); + kfree(cfi->cmdset_priv); + kfree(mtd); + return NULL; + } - for (i=0; i<mtd->numeraseregions;i++){ - printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n", - i, (unsigned long long)mtd->eraseregions[i].offset, - mtd->eraseregions[i].erasesize, - mtd->eraseregions[i].numblocks); - } + for (i=0; i<mtd->numeraseregions;i++){ + printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n", + i, (unsigned long long)mtd->eraseregions[i].offset, + mtd->eraseregions[i].erasesize, + mtd->eraseregions[i].numblocks); + } /* Also select the correct geometry setup too */ mtd->_erase = cfi_staa_erase_varsize; diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 66f0405f7e53..b16f3cda97ff 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -9,7 +9,15 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +/* + * When the first attempt at device initialization fails, we may need to + * wait a little bit and retry. This timeout, by default 3 seconds, gives + * device time to start up. Required on BCM2708 and a few other chipsets. + */ +#define MTD_DEFAULT_TIMEOUT 3 + #include <linux/module.h> +#include <linux/delay.h> #include <linux/fs.h> #include <linux/blkdev.h> #include <linux/bio.h> @@ -209,10 +217,14 @@ static void block2mtd_free_device(struct block2mtd_dev *dev) } -static struct block2mtd_dev *add_device(char *devname, int erase_size) +static struct block2mtd_dev *add_device(char *devname, int erase_size, + int timeout) { +#ifndef MODULE + int i; +#endif const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; - struct block_device *bdev; + struct block_device *bdev = ERR_PTR(-ENODEV); struct block2mtd_dev *dev; char *name; @@ -225,15 +237,28 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) /* Get a handle on the device */ bdev = blkdev_get_by_path(devname, mode, dev); -#ifndef MODULE - if (IS_ERR(bdev)) { - - /* We might not have rootfs mounted at this point. Try - to resolve the device name by other means. */ - dev_t devt = name_to_dev_t(devname); - if (devt) - bdev = blkdev_get_by_dev(devt, mode, dev); +#ifndef MODULE + /* + * We might not have the root device mounted at this point. + * Try to resolve the device name by other means. + */ + for (i = 0; IS_ERR(bdev) && i <= timeout; i++) { + dev_t devt; + + if (i) + /* + * Calling wait_for_device_probe in the first loop + * was not enough, sleep for a bit in subsequent + * go-arounds. + */ + msleep(1000); + wait_for_device_probe(); + + devt = name_to_dev_t(devname); + if (!devt) + continue; + bdev = blkdev_get_by_dev(devt, mode, dev); } #endif @@ -280,6 +305,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) /* Device didn't get added, so free the entry */ goto err_destroy_mutex; } + list_add(&dev->list, &blkmtd_device_list); pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", dev->mtd.index, @@ -348,16 +374,19 @@ static inline void kill_final_newline(char *str) #ifndef MODULE static int block2mtd_init_called = 0; -static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */ +/* 80 for device, 12 for erase size */ +static char block2mtd_paramline[80 + 12]; #endif static int block2mtd_setup2(const char *val) { - char buf[80 + 12]; /* 80 for device, 12 for erase size */ + /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ + char buf[80 + 12 + 80 + 8]; char *str = buf; char *token[2]; char *name; size_t erase_size = PAGE_SIZE; + unsigned long timeout = MTD_DEFAULT_TIMEOUT; int i, ret; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) { @@ -395,7 +424,7 @@ static int block2mtd_setup2(const char *val) } } - add_device(name, erase_size); + add_device(name, erase_size, timeout); return 0; } @@ -463,8 +492,7 @@ static void block2mtd_exit(void) } } - -module_init(block2mtd_init); +late_initcall(block2mtd_init); module_exit(block2mtd_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 448ce42f951e..866d31904475 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1805,7 +1805,7 @@ static int __init doc_dbg_register(struct docg3 *docg3) } } -static void __exit doc_dbg_unregister(struct docg3 *docg3) +static void doc_dbg_unregister(struct docg3 *docg3) { debugfs_remove_recursive(docg3->debugfs_root); } @@ -2033,7 +2033,7 @@ static int __init docg3_probe(struct platform_device *pdev) struct mtd_info *mtd; struct resource *ress; void __iomem *base; - int ret, floor, found = 0; + int ret, floor; struct docg3_cascade *cascade; ret = -ENXIO; @@ -2073,14 +2073,11 @@ static int __init docg3_probe(struct platform_device *pdev) 0); if (ret) goto err_probe; - found++; } ret = doc_register_sysfs(pdev, cascade); if (ret) goto err_probe; - if (!found) - goto notfound; platform_set_drvdata(pdev, cascade); doc_dbg_register(cascade->floors[0]->priv); @@ -2103,7 +2100,7 @@ err_probe: * * Returns 0 */ -static int __exit docg3_release(struct platform_device *pdev) +static int docg3_release(struct platform_device *pdev) { struct docg3_cascade *cascade = platform_get_drvdata(pdev); struct docg3 *docg3 = cascade->floors[0]->priv; @@ -2134,7 +2131,7 @@ static struct platform_driver g3_driver = { }, .suspend = docg3_suspend, .resume = docg3_resume, - .remove = __exit_p(docg3_release), + .remove = docg3_release, }; module_platform_driver_probe(g3_driver, docg3_probe); diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 85e35467fba6..7c8b1694a134 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -223,6 +223,8 @@ static int m25p_probe(struct spi_device *spi) */ if (data && data->type) flash_name = data->type; + else if (!strcmp(spi->modalias, "nor-jedec")) + flash_name = NULL; /* auto-detect */ else flash_name = spi->modalias; @@ -247,9 +249,16 @@ static int m25p_remove(struct spi_device *spi) } /* - * XXX This needs to be kept in sync with spi_nor_ids. We can't share - * it with spi-nor, because if this is built as a module then modpost - * won't be able to read it and add appropriate aliases. + * Do NOT add to this array without reading the following: + * + * Historically, many flash devices are bound to this driver by their name. But + * since most of these flash are compatible to some extent, and their + * differences can often be differentiated by the JEDEC read-ID command, we + * encourage new users to add support to the spi-nor library, and simply bind + * against a generic string here (e.g., "nor-jedec"). + * + * Many flash names are kept here in this list (as well as in spi-nor.c) to + * keep them available as module aliases for existing platforms. */ static const struct spi_device_id m25p_ids[] = { {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, @@ -291,6 +300,12 @@ static const struct spi_device_id m25p_ids[] = { {"w25x64"}, {"w25q64"}, {"w25q80"}, {"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"}, {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, + + /* + * Generic support for SPI NOR that can be identified by the JEDEC READ + * ID opcode (0x9F). Use this, if possible. + */ + {"nor-jedec"}, { }, }; MODULE_DEVICE_TABLE(spi, m25p_ids); diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index ba801d2c6dcc..e715ae90632f 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -242,7 +242,7 @@ config MTD_L440GX config MTD_CFI_FLAGADM tristate "CFI Flash device mapping on FlagaDM" - depends on 8xx && MTD_CFI + depends on PPC_8xx && MTD_CFI help Mapping for the Flaga digital module. If you don't have one, ignore this setting. diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index ea697202935a..892ad6ac63f2 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -274,7 +274,7 @@ static int sa1100_mtd_probe(struct platform_device *pdev) return err; } -static int __exit sa1100_mtd_remove(struct platform_device *pdev) +static int sa1100_mtd_remove(struct platform_device *pdev) { struct sa_info *info = platform_get_drvdata(pdev); struct flash_platform_data *plat = dev_get_platdata(&pdev->dev); @@ -286,7 +286,7 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev) static struct platform_driver sa1100_mtd_driver = { .probe = sa1100_mtd_probe, - .remove = __exit_p(sa1100_mtd_remove), + .remove = sa1100_mtd_remove, .driver = { .name = "sa1100-mtd", }, diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index d1d671daf235..9969fedb1f13 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c @@ -117,5 +117,5 @@ module_exit(cleanup_ts5500_map); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sean Young <sean@mess.org>"); -MODULE_DESCRIPTION("MTD map driver for Techology Systems TS-5500 board"); +MODULE_DESCRIPTION("MTD map driver for Technology Systems TS-5500 board"); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index d08229eb44d8..2b0c52870999 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -171,9 +171,6 @@ static void mtd_blktrans_work(struct work_struct *work) background_done = 0; } - if (req) - __blk_end_request_all(req, -EIO); - spin_unlock_irq(rq->queue_lock); } diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 11883bd26d9d..d172195fbd15 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -38,6 +38,7 @@ #include <linux/gfp.h> #include <linux/slab.h> #include <linux/reboot.h> +#include <linux/kconfig.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> @@ -501,6 +502,29 @@ out_error: return ret; } +static int mtd_add_device_partitions(struct mtd_info *mtd, + struct mtd_partition *real_parts, + int nbparts) +{ + int ret; + + if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { + ret = add_mtd_device(mtd); + if (ret == 1) + return -ENODEV; + } + + if (nbparts > 0) { + ret = add_mtd_partitions(mtd, real_parts, nbparts); + if (ret && IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + del_mtd_device(mtd); + return ret; + } + + return 0; +} + + /** * mtd_device_parse_register - parse partitions and register an MTD device. * @@ -523,7 +547,8 @@ out_error: * found this functions tries to fallback to information specified in * @parts/@nr_parts. * * If any partitioning info was found, this function registers the found - * partitions. + * partitions. If the MTD_PARTITIONED_MASTER option is set, then the device + * as a whole is registered first. * * If no partitions were found this function just registers the MTD device * @mtd and exits. * @@ -534,27 +559,21 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, const struct mtd_partition *parts, int nr_parts) { - int err; - struct mtd_partition *real_parts; + int ret; + struct mtd_partition *real_parts = NULL; - err = parse_mtd_partitions(mtd, types, &real_parts, parser_data); - if (err <= 0 && nr_parts && parts) { + ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data); + if (ret <= 0 && nr_parts && parts) { real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, GFP_KERNEL); if (!real_parts) - err = -ENOMEM; + ret = -ENOMEM; else - err = nr_parts; + ret = nr_parts; } - if (err > 0) { - err = add_mtd_partitions(mtd, real_parts, err); - kfree(real_parts); - } else if (err == 0) { - err = add_mtd_device(mtd); - if (err == 1) - err = -ENODEV; - } + if (ret >= 0) + ret = mtd_add_device_partitions(mtd, real_parts, ret); /* * FIXME: some drivers unfortunately call this function more than once. @@ -569,7 +588,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, register_reboot_notifier(&mtd->reboot_notifier); } - return err; + kfree(real_parts); + return ret; } EXPORT_SYMBOL_GPL(mtd_device_parse_register); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index e779de315ade..cafdb8855a79 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -30,6 +30,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/err.h> +#include <linux/kconfig.h> #include "mtdcore.h" @@ -379,10 +380,17 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, slave->mtd.name = name; slave->mtd.owner = master->owner; - /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone - * to have the same data be in two different partitions. + /* NOTE: Historically, we didn't arrange MTDs as a tree out of + * concern for showing the same data in multiple partitions. + * However, it is very useful to have the master node present, + * so the MTD_PARTITIONED_MASTER option allows that. The master + * will have device nodes etc only if this is set, so make the + * parent conditional on that option. Note, this is a way to + * distinguish between the master and the partition in sysfs. */ - slave->mtd.dev.parent = master->dev.parent; + slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ? + &master->dev : + master->dev.parent; slave->mtd._read = part_read; slave->mtd._write = part_write; @@ -546,12 +554,35 @@ out_register: return slave; } +static ssize_t mtd_partition_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + struct mtd_part *part = PART(mtd); + return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset); +} + +static DEVICE_ATTR(offset, S_IRUGO, mtd_partition_offset_show, NULL); + +static const struct attribute *mtd_partition_attrs[] = { + &dev_attr_offset.attr, + NULL +}; + +static int mtd_add_partition_attrs(struct mtd_part *new) +{ + int ret = sysfs_create_files(&new->mtd.dev.kobj, mtd_partition_attrs); + if (ret) + printk(KERN_WARNING + "mtd: failed to create partition attrs, err=%d\n", ret); + return ret; +} + int mtd_add_partition(struct mtd_info *master, const char *name, long long offset, long long length) { struct mtd_partition part; - struct mtd_part *p, *new; - uint64_t start, end; + struct mtd_part *new; int ret = 0; /* the direct offset is expected */ @@ -575,31 +606,15 @@ int mtd_add_partition(struct mtd_info *master, const char *name, if (IS_ERR(new)) return PTR_ERR(new); - start = offset; - end = offset + length; - mutex_lock(&mtd_partitions_mutex); - list_for_each_entry(p, &mtd_partitions, list) - if (p->master == master) { - if ((start >= p->offset) && - (start < (p->offset + p->mtd.size))) - goto err_inv; - - if ((end >= p->offset) && - (end < (p->offset + p->mtd.size))) - goto err_inv; - } - list_add(&new->list, &mtd_partitions); mutex_unlock(&mtd_partitions_mutex); add_mtd_device(&new->mtd); + mtd_add_partition_attrs(new); + return ret; -err_inv: - mutex_unlock(&mtd_partitions_mutex); - free_partition(new); - return -EINVAL; } EXPORT_SYMBOL_GPL(mtd_add_partition); @@ -612,6 +627,8 @@ int mtd_del_partition(struct mtd_info *master, int partno) list_for_each_entry_safe(slave, next, &mtd_partitions, list) if ((slave->master == master) && (slave->mtd.index == partno)) { + sysfs_remove_files(&slave->mtd.dev.kobj, + mtd_partition_attrs); ret = del_mtd_device(&slave->mtd); if (ret < 0) break; @@ -631,8 +648,8 @@ EXPORT_SYMBOL_GPL(mtd_del_partition); * and registers slave MTD objects which are bound to the master according to * the partition definitions. * - * We don't register the master, or expect the caller to have done so, - * for reasons of data integrity. + * For historical reasons, this function's caller only registers the master + * if the MTD_PARTITIONED_MASTER config option is set. */ int add_mtd_partitions(struct mtd_info *master, @@ -655,6 +672,7 @@ int add_mtd_partitions(struct mtd_info *master, mutex_unlock(&mtd_partitions_mutex); add_mtd_device(&slave->mtd); + mtd_add_partition_attrs(slave); cur_offset = slave->offset + slave->mtd.size; } diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index d93c849b70b5..46010bd895b1 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -485,7 +485,7 @@ static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, for (i = 0; i < ecc_len; i++) layout->eccpos[i] = oobsize - ecc_len + i; - layout->oobfree[0].offset = 2; + layout->oobfree[0].offset = PMECC_OOB_RESERVED_BYTES; layout->oobfree[0].length = oobsize - ecc_len - layout->oobfree[0].offset; } @@ -1204,14 +1204,14 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, goto err; } - regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); - host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); - if (IS_ERR(host->pmecc_rom_base)) { - if (!host->has_no_lookup_table) - /* Don't display the information again */ + if (!host->has_no_lookup_table) { + regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); + host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, + regs_rom); + if (IS_ERR(host->pmecc_rom_base)) { dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n"); - - host->has_no_lookup_table = true; + host->has_no_lookup_table = true; + } } if (host->has_no_lookup_table) { @@ -1254,7 +1254,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, nand_chip->ecc.steps = mtd->writesize / sector_size; nand_chip->ecc.total = nand_chip->ecc.bytes * nand_chip->ecc.steps; - if (nand_chip->ecc.total > mtd->oobsize - 2) { |