diff options
Diffstat (limited to 'drivers/mtd')
59 files changed, 971 insertions, 883 deletions
diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 7a6384b..9279a91 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -27,13 +27,11 @@ /* Magics */ #define BOARD_DATA_MAGIC 0x5246504D /* MPFR */ -#define FACTORY_MAGIC 0x59544346 /* FCTY */ #define POT_MAGIC1 0x54544f50 /* POTT */ #define POT_MAGIC2 0x504f /* OP */ #define ML_MAGIC1 0x39685a42 #define ML_MAGIC2 0x26594131 #define TRX_MAGIC 0x30524448 -#define SQSH_MAGIC 0x71736873 /* shsq */ struct trx_header { uint32_t magic; @@ -73,14 +71,7 @@ static int bcm47xxpart_parse(struct mtd_info *master, /* Alloc */ parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS, GFP_KERNEL); - if (!parts) - return -ENOMEM; - buf = kzalloc(BCM47XXPART_BYTES_TO_READ, GFP_KERNEL); - if (!buf) { - kfree(parts); - return -ENOMEM; - } /* Parse block by block looking for magics */ for (offset = 0; offset <= master->size - blocksize; @@ -119,13 +110,6 @@ static int bcm47xxpart_parse(struct mtd_info *master, continue; } - /* Found on Huawei E970 */ - if (buf[0x000 / 4] == FACTORY_MAGIC) { - bcm47xxpart_add_part(&parts[curr_part++], "factory", - offset, MTD_WRITEABLE); - continue; - } - /* POT(TOP) */ if (buf[0x000 / 4] == POT_MAGIC1 && (buf[0x004 / 4] & 0xFFFF) == POT_MAGIC2) { @@ -183,13 +167,6 @@ static int bcm47xxpart_parse(struct mtd_info *master, offset = rounddown(offset + trx->length, blocksize); continue; } - - /* Squashfs on devices not using TRX */ - if (buf[0x000 / 4] == SQSH_MAGIC) { - bcm47xxpart_add_part(&parts[curr_part++], "rootfs", - offset, 0); - continue; - } } /* Look for NVRAM at the end of the last block. */ diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 0128138..74ab4b7 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -95,6 +95,13 @@ config MTD_M25P80 if you want to specify device partitioning or to use a device which doesn't support the JEDEC ID instruction. +config M25PXX_USE_FAST_READ + bool "Use FAST_READ OPCode allowing SPI CLK >= 50MHz" + depends on MTD_M25P80 + default y + help + This option enables FAST_READ access supported by ST M25Pxx. + config MTD_SPEAR_SMI tristate "SPEAR MTD NOR Support through SMI controller" depends on PLAT_SPEAR diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index d9fd87a..5cb4c04 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -20,7 +20,6 @@ #include <linux/mutex.h> #include <linux/mount.h> #include <linux/slab.h> -#include <linux/major.h> /* Info for the block device */ struct block2mtd_dev { diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 4f091c1..3e1b0a0 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -2097,7 +2097,7 @@ notfound: ret = -ENODEV; dev_info(dev, "No supported DiskOnChip found\n"); err_probe: - free_bch(cascade->bch); + kfree(cascade->bch); for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) if (cascade->floors[floor]) doc_release_device(cascade->floors[floor]); diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7eda71d..6bc9618 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -78,7 +78,7 @@ /* Define max times to check status register before we give up. */ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ -#define MAX_CMD_SIZE 6 +#define MAX_CMD_SIZE 5 #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) @@ -367,6 +367,10 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, spi_message_init(&m); memset(t, 0, (sizeof t)); + /* NOTE: + * OPCODE_FAST_READ (if available) is faster. + * Should add 1 byte DUMMY_BYTE. + */ t[0].tx_buf = flash->command; t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0); spi_message_add_tail(&t[0], &m); @@ -384,6 +388,11 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, return 1; } + /* FIXME switch to OPCODE_FAST_READ. It's required for higher + * clocks; and at this writing, every chip this driver handles + * supports that opcode. + */ + /* Set up the write data buffer. */ opcode = flash->read_opcode; flash->command[0] = opcode; @@ -740,19 +749,16 @@ static const struct spi_device_id m25p_ids[] = { { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, /* EON -- en25xxx */ - { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, - { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, - { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, - { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, - { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, - { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, - - /* ESMT */ - { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, + { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, + { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, + { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, + { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, + { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, + { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, /* Everspin */ - { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) }, - { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) }, + { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) }, + { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) }, /* GigaDevice */ { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, @@ -769,7 +775,6 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, - { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, @@ -778,16 +783,15 @@ static const struct spi_device_id m25p_ids[] = { { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 0) }, /* Micron */ - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, - { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, - { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, - { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, - { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) }, + { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, + { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, + { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, + { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, /* PMC */ - { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, - { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, - { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, + { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, + { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, + { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). @@ -936,7 +940,12 @@ static int m25p_probe(struct spi_device *spi) struct flash_info *info; unsigned i; struct mtd_part_parser_data ppdata; - struct device_node *np = spi->dev.of_node; + struct device_node __maybe_unused *np = spi->dev.of_node; + +#ifdef CONFIG_MTD_OF_PARTS + if (!of_device_is_available(np)) + return -ENODEV; +#endif /* Platform data helps sort out which chip type we have, as * well as how this board partitions it. If we don't have @@ -983,13 +992,15 @@ static int m25p_probe(struct spi_device *spi) } } - flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); + flash = kzalloc(sizeof *flash, GFP_KERNEL); if (!flash) return -ENOMEM; - - flash->command = devm_kzalloc(&spi->dev, MAX_CMD_SIZE, GFP_KERNEL); - if (!flash->command) + flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0), + GFP_KERNEL); + if (!flash->command) { + kfree(flash); return -ENOMEM; + } flash->spi = spi; mutex_init(&flash->lock); @@ -1051,14 +1062,13 @@ static int m25p_probe(struct spi_device *spi) flash->page_size = info->page_size; flash->mtd.writebufsize = flash->page_size; - if (np) - /* If we were instantiated by DT, use it */ - flash->fast_read = of_property_read_bool(np, "m25p,fast-read"); - else - /* If we weren't instantiated by DT, default to fast-read */ + flash->fast_read = false; + if (np && of_property_read_bool(np, "m25p,fast-read")) flash->fast_read = true; - /* Some devices cannot do fast-read, no matter what DT tells us */ +#ifdef CONFIG_M25PXX_USE_FAST_READ + flash->fast_read = true; +#endif if (info->flags & M25P_NO_FR) flash->fast_read = false; @@ -1123,9 +1133,15 @@ static int m25p_probe(struct spi_device *spi) static int m25p_remove(struct spi_device *spi) { struct m25p *flash = spi_get_drvdata(spi); + int status; /* Clean up MTD stuff. */ - return mtd_device_unregister(&flash->mtd); + status = mtd_device_unregister(&flash->mtd); + if (status == 0) { + kfree(flash->command); + kfree(flash); + } + return 0; } diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 4a47b02..0e8cbfe 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -88,6 +88,8 @@ struct dataflash { uint8_t command[4]; char name[24]; + unsigned partitioned:1; + unsigned short page_offset; /* offset in flash address */ unsigned int page_size; /* of bytes per page */ @@ -879,7 +881,7 @@ static int dataflash_probe(struct spi_device *spi) break; /* obsolete AT45DB1282 not (yet?) supported */ default: - dev_info(&spi->dev, "unsupported device (%x)\n", + pr_debug("%s: unsupported device (%x)\n", dev_name(&spi->dev), status & 0x3c); status = -ENODEV; } diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index e1f2aeb..67823de 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -94,7 +94,7 @@ static void unregister_devices(void) } } -static int register_device(char *name, phys_addr_t start, size_t len) +static int register_device(char *name, unsigned long start, unsigned long len) { struct phram_mtd_list *new; int ret = -ENOMEM; @@ -141,35 +141,35 @@ out0: return ret; } -static int parse_num64(uint64_t *num64, char *token) +static int ustrtoul(const char *cp, char **endp, unsigned int base) { - size_t len; - int shift = 0; - int ret; - - len = strlen(token); + unsigned long result = simple_strtoul(cp, endp, base); + + switch (**endp) { + case 'G': + result *= 1024; + case 'M': + result *= 1024; + case 'k': + result *= 1024; /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */ - if (len > 2) { - if (token[len - 1] == 'i') { - switch (token[len - 2]) { - case 'G': - shift += 10; - case 'M': - shift += 10; - case 'k': - shift += 10; - token[len - 2] = 0; - break; - default: - return -EINVAL; - } - } + if ((*endp)[1] == 'i') + (*endp) += 2; } + return result; +} - ret = kstrtou64(token, 0, num64); - *num64 <<= shift; +static int parse_num32(uint32_t *num32, const char *token) +{ + char *endp; + unsigned long n; - return ret; + n = ustrtoul(token, &endp, 0); + if (*endp) + return -EINVAL; + + *num32 = n; + return 0; } static int parse_name(char **pname, const char *token) @@ -209,19 +209,19 @@ static inline void kill_final_newline(char *str) * This shall contain the module parameter if any. It is of the form: * - phram=<device>,<address>,<size> for module case * - phram.phram=<device>,<address>,<size> for built-in case - * We leave 64 bytes for the device name, 20 for the address and 20 for the + * We leave 64 bytes for the device name, 12 for the address and 12 for the * size. * Example: phram.phram=rootfs,0xa0000000,512Mi */ -static __initdata char phram_paramline[64 + 20 + 20]; +static __initdata char phram_paramline[64+12+12]; static int __init phram_setup(const char *val) { - char buf[64 + 20 + 20], *str = buf; + char buf[64+12+12], *str = buf; char *token[3]; char *name; - uint64_t start; - uint64_t len; + uint32_t start; + uint32_t len; int i, ret; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) @@ -243,13 +243,13 @@ static int __init phram_setup(const char *val) if (ret) return ret; - ret = parse_num64(&start, token[1]); + ret = parse_num32(&start, token[1]); if (ret) { kfree(name); parse_err("illegal start address\n"); } - ret = parse_num64(&len, token[2]); + ret = parse_num32(&len, token[2]); if (ret) { kfree(name); parse_err("illegal device length\n"); @@ -257,7 +257,7 @@ static int __init phram_setup(const char *val) ret = register_device(name, start, len); if (!ret) - pr_info("%s device: %#llx at %#llx\n", name, len, start); + pr_info("%s device: %#x at %#x\n", name, len, start); else kfree(name); diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 687bf27..a42f1f0 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -364,7 +364,7 @@ static int sst25l_probe(struct spi_device *spi) if (!flash_info) return -ENODEV; - flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); + flash = kzalloc(sizeof(struct sst25l_flash), GFP_KERNEL); if (!flash) return -ENOMEM; @@ -402,8 +402,11 @@ static int sst25l_probe(struct spi_device *spi) ret = mtd_device_parse_register(&flash->mtd, NULL, NULL, data ? data->parts : NULL, data ? data->nr_parts : 0); - if (ret) + if (ret) { + kfree(flash); + spi_set_drvdata(spi, NULL); return -ENODEV; + } return 0; } @@ -411,8 +414,12 @@ static int sst25l_probe(struct spi_device *spi) static int sst25l_remove(struct spi_device *spi) { struct sst25l_flash *flash = spi_get_drvdata(spi); + int ret; - return mtd_device_unregister(&flash->mtd); + ret = mtd_device_unregister(&flash->mtd); + if (ret == 0) + kfree(flash); + return ret; } static struct spi_driver sst25l_driver = { diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index b66b541..3af3514 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -50,7 +50,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) struct INFTLrecord *inftl; unsigned long temp; - if (!mtd_type_is_nand(mtd) || mtd->size > UINT_MAX) + if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX) return; /* OK, this is moderately ugly. But probably safe. Alternatives? */ if (memcmp(mtd->name, "DiskOnChip", 10)) diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 2ef19aa..d3cfe26b 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -703,7 +703,7 @@ static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr) #define DO_XXLOCK_LOCK 1 #define DO_XXLOCK_UNLOCK 2 -static int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk) +int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk) { int ret = 0; struct map_info *map = mtd->priv; diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index 46d195f..f581ac1 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -180,6 +180,7 @@ static void vr_nor_pci_remove(struct pci_dev *dev) { struct vr_nor_mtd *p = pci_get_drvdata(dev); + pci_set_drvdata(dev, NULL); vr_nor_destroy_partitions(p); vr_nor_destroy_mtd_setup(p); vr_nor_destroy_maps(p); diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index 36da518..c2604f8 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -316,6 +316,7 @@ static void mtd_pci_remove(struct pci_dev *dev) map->exit(dev, map); kfree(map); + pci_set_drvdata(dev, NULL); pci_release_regions(dev); } diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 10196f5..6762716 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -55,7 +55,7 @@ struct platram_info { static inline struct platram_info *to_platram_info(struct platform_device *dev) { - return platform_get_drvdata(dev); + return (struct platram_info *)platform_get_drvdata(dev); } /* platram_setrw @@ -257,7 +257,21 @@ static struct platform_driver platram_driver = { }, }; -module_platform_driver(platram_driver); +/* module init/exit */ + +static int __init platram_init(void) +{ + printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n"); + return platform_driver_register(&platram_driver); +} + +static void __exit platram_exit(void) +{ + platform_driver_unregister(&platram_driver); +} + +module_init(platram_init); +module_exit(platram_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index 3051c4c..c77b68c 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -212,6 +212,7 @@ static void scb2_flash_remove(struct pci_dev *dev) if (!region_fail) release_mem_region(SCB2_ADDR, SCB2_WINDOW); + pci_set_drvdata(dev, NULL); } static struct pci_device_id scb2_flash_pci_ids[] = { diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 485ea75..2aef5dd 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -32,7 +32,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/blktrans.h> #include <linux/mutex.h> -#include <linux/major.h> struct mtdblk_dev { @@ -374,7 +373,7 @@ static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) static struct mtd_blktrans_ops mtdblock_tr = { .name = "mtdblock", - .major = MTD_BLOCK_MAJOR, + .major = 31, .part_bits = 0, .blksize = 512, .open = mtdblock_open, diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index fb5dc89..92759a9 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -24,7 +24,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/blktrans.h> #include <linux/module.h> -#include <linux/major.h> static int mtdblock_readsect(struct mtd_blktrans_dev *dev, unsigned long block, char *buf) @@ -71,7 +70,7 @@ static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) static struct mtd_blktrans_ops mtdblock_tr = { .name = "mtdblock", - .major = MTD_BLOCK_MAJOR, + .major = 31, .part_bits = 0, .blksize = 512, .readsect = mtdblock_readsect, diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 2147e73..684bfa3 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -32,7 +32,6 @@ #include <linux/mount.h> #include <linux/blkpg.h> #include <linux/magic.h> -#include <linux/major.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/mtd/map.h> @@ -1100,7 +1099,7 @@ static unsigned long mtdchar_get_unmapped_area(struct file *file, return (unsigned long) -EINVAL; ret = mtd_get_unmapped_area(mtd, len, offset, flags); - return ret == -EOPNOTSUPP ? -ENODEV : ret; + return ret == -EOPNOTSUPP ? -ENOSYS : ret; } #endif @@ -1125,9 +1124,9 @@ static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma) #endif return vm_iomap_memory(vma, map->phys, map->size); } - return -ENODEV; + return -ENOSYS; #else - return vma->vm_flags & VM_SHARED ? 0 : -EACCES; + return vma->vm_flags & VM_SHARED ? 0 : -ENOSYS; #endif } diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 92311a5..5e14d54 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -157,9 +157,6 @@ static ssize_t mtd_type_show(struct device *dev, case MTD_UBIVOLUME: type = "ubi"; break; - case MTD_MLCNANDFLASH: - type = "mlc-nand"; - break; default: type = "unknown"; } diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 20c02a3..334da5f 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -17,7 +17,6 @@ #include <linux/export.h> #include <linux/ctype.h> #include <linux/slab.h> -#include <linux/major.h> /* * compare superblocks to see if they're equivalent diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 93ae6a6..d885298 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -96,15 +96,43 @@ config MTD_NAND_OMAP2 config MTD_NAND_OMAP_BCH depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3 - tristate "Support hardware based BCH error correction" + tristate "Enable support for hardware BCH error correction" default n select BCH + select BCH_CONST_PARAMS help - This config enables the ELM hardware engine, which can be used to - locate and correct errors when using BCH ECC scheme. This offloads - the cpu from doing ECC error searching and correction. However some - legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine - so they should not enable this config symbol. + Support for hardware BCH error correction. + +choice + prompt "BCH error correction capability" + depends on MTD_NAND_OMAP_BCH + +config MTD_NAND_OMAP_BCH8 + bool "8 bits / 512 bytes (recommended)" + help + Support correcting up to 8 bitflips per 512-byte block. + This will use 13 bytes of spare area per 512 bytes of page data. + This is the recommended mode, as 4-bit mode does not work + on some OMAP3 revisions, due to a hardware bug. + +config MTD_NAND_OMAP_BCH4 + bool "4 bits / 512 bytes" + help + Support correcting up to 4 bitflips per 512-byte block. + This will use 7 bytes of spare area per 512 bytes of page data. + Note that this mode does not work on some OMAP3 revisions, due to a + hardware bug. Please check your OMAP datasheet before selecting this + mode. + +endchoice + +if MTD_NAND_OMAP_BCH +config BCH_CONST_M + default 13 +config BCH_CONST_T + default 4 if MTD_NAND_OMAP_BCH4 + default 8 if MTD_NAND_OMAP_BCH8 +endif config MTD_NAND_IDS tristate diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 59f08c4..060feea 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -375,7 +375,8 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, dma_dev = host->dma_chan->device; - flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP | + DMA_COMPL_SKIP_DEST_UNMAP; phys_addr = dma_map_single(dma_dev->dev, p, len, dir); if (dma_mapping_error(dma_dev->dev, phys_addr)) { @@ -1061,28 +1062,56 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) } /* - * Get minimum ecc requirements from NAND. + * Get ECC requirement in ONFI parameters, returns -1 if ONFI + * parameters is not supported. + * return 0 if success to get the ECC requirement. + */ +static int get_onfi_ecc_param(struct nand_chip *chip, + int *ecc_bits, int *sector_size) +{ + *ecc_bits = *sector_size = 0; + + if (chip->onfi_params.ecc_bits == 0xff) + /* TODO: the sector_size and ecc_bits need to be find in + * extended ecc parameter, currently we don't support it. + */ + return -1; + + *ecc_bits = chip->onfi_params.ecc_bits; + + /* The default sector size (ecc codeword size) is 512 */ + *sector_size = 512; + + return 0; +} + +/* + * Get ecc requirement from ONFI parameters ecc requirement. * If pmecc-cap, pmecc-sector-size in DTS are not specified, this function - * will set them according to minimum ecc requirement. Otherwise, use the + * will set them according to ONFI ecc requirement. Otherwise, use the * value in DTS file. * return 0 if success. otherwise return error code. */ static int pmecc_choose_ecc(struct atmel_nand_host *host, int *cap, int *sector_size) { - /* Get minimum ECC requirements */ - if (host->nand_chip.ecc_strength_ds) { - *cap = host->nand_chip.ecc_strength_ds; - *sector_size = host->nand_chip.ecc_step_ds; - dev_info(host->dev, "minimum ECC: %d bits in %d bytes\n", + /* Get ECC requirement from ONFI parameters */ + *cap = *sector_size = 0; + if (host->nand_chip.onfi_version) { + if (!get_onfi_ecc_param(&host->nand_chip, cap, sector_size)) + dev_info(host->dev, "ONFI params, minimum required ECC: %d bits in %d bytes\n", *cap, *sector_size); + else + dev_info(host->dev, "NAND chip ECC reqirement is in Extended ONFI parameter, we don't support yet.\n"); } else { + dev_info(host->dev, "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes"); + } + if (*cap == 0 && *sector_size == 0) { *cap = 2; *sector_size = 512; - dev_info(host->dev, "can't detect min. ECC, assume 2 bits in 512 bytes\n"); } - /* If device tree doesn't specify, use NAND's minimum ECC parameters */ + /* If dts file doesn't specify then use the one in ONFI parameters */ if (host->pmecc_corr_cap == 0) { /* use the most fitable ecc bits (the near bigger one ) */ if (*cap <= 2) @@ -1110,7 +1139,7 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, return 0; } -static int atmel_pmecc_nand_init_params(struct platform_device *pdev, +static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev, struct atmel_nand_host *host) { struct mtd_info *mtd = &host->mtd; @@ -1420,6 +1449,7 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) ecc_writel(host->ecc, CR, ATMEL_ECC_RST); } +#if defined(CONFIG_OF) static int atmel_of_init_port(struct atmel_nand_host *host, struct device_node *np) { @@ -1427,7 +1457,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host, u32 offset[2]; int ecc_mode; struct atmel_nand_data *board = &host->board; - enum of_gpio_flags flags = 0; + enum of_gpio_flags flags; if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) { if (val >= 32) { @@ -1510,8 +1540,15 @@ static int atmel_of_init_port(struct atmel_nand_host *host, return 0; } +#else +static int atmel_of_init_port(struct atmel_nand_host *host, + struct device_node *np) +{ + return -EINVAL; +} +#endif -static int atmel_hw_nand_init_params(struct platform_device *pdev, +static int __init atmel_hw_nand_init_params(struct platform_device *pdev, struct atmel_nand_host *host) { struct mtd_info *mtd = &host->mtd; @@ -1950,7 +1987,7 @@ static struct platform_driver atmel_nand_nfc_driver; /* * Probe for the NAND device. */ -static int atmel_nand_probe(struct platform_device *pdev) +static int __init atmel_nand_probe(struct platform_device *pdev) { struct atmel_nand_host *host; struct mtd_info *mtd; @@ -1982,8 +2019,7 @@ static int atmel_nand_probe(struct platform_device *pdev) mtd = &host->mtd; nand_chip = &host->nand_chip; host->dev = &pdev->dev; - if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { - /* Only when CONFIG_OF is enabled of_node can be parsed */ + if (pdev->dev.of_node) { res = atmel_of_init_port(host, pdev->dev.of_node); if (res) goto err_nand_ioremap; @@ -2141,13 +2177,14 @@ err_no_card: if (host->dma_chan) dma_release_channel(host->dma_chan); err_nand_ioremap: + platform_driver_unregister(&atmel_nand_nfc_driver); return res; } /* * Remove a NAND device. */ -static int atmel_nand_remove(struct platform_device *pdev) +static int __exit atmel_nand_remove(struct platform_device *pdev) { struct atmel_nand_host *host = platform_get_drvdata(pdev); struct mtd_info *mtd = &host->mtd; @@ -2170,12 +2207,14 @@ static int atmel_nand_remove(struct platform_device *pdev) return 0; } +#if defined(CONFIG_OF) static const struct of_device_id atmel_nand_dt_ids[] = { { .compatible = "atmel,at91rm9200-nand" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids); +#endif static int atmel_nand_nfc_probe(struct platform_device *pdev) { @@ -2214,11 +2253,12 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id atmel_nand_nfc_match[] = { +#if defined(CONFIG_OF) +static struct of_device_id atmel_nand_nfc_match[] = { { .compatible = "atmel,sama5d3-nfc" }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, atmel_nand_nfc_match); +#endif static struct platform_driver atmel_nand_nfc_driver = { .driver = { @@ -2230,8 +2270,7 @@ static struct platform_driver atmel_nand_nfc_driver = { }; static struct platform_driver atmel_nand_driver = { - .probe = atmel_nand_probe, - .remove = atmel_nand_remove, + .remove = __exit_p(atmel_nand_remove), .driver = { .name = "atmel_nand", .owner = THIS_MODULE, @@ -2239,7 +2278,7 @@ static struct platform_driver atmel_nand_driver = { }, }; -module_platform_driver(atmel_nand_driver); +module_platform_driver_probe(atmel_nand_driver, atmel_nand_probe); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Rick Bronson"); diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c index 1074459..7bae569 100644 --- a/drivers/mtd/nand/bcm47xxnflash/main.c +++ b/drivers/mtd/nand/bcm47xxnflash/main.c @@ -29,9 +29,11 @@ static int bcm47xxnflash_probe(struct platform_device *pdev) struct bcm47xxnflash *b47n; int err = 0; - b47n = devm_kzalloc(&pdev->dev, sizeof(*b47n), GFP_KERNEL); - if (!b47n) - return -ENOMEM; + b47n = kzalloc(sizeof(*b47n), GFP_KERNEL); + if (!b47n) { + err = -ENOMEM; + goto out; + } b47n->nand_chip.priv = b47n; b47n->mtd.owner = THIS_MODULE; @@ -46,16 +48,22 @@ static int bcm47xxnflash_probe(struct platform_device *pdev) } if (err) { pr_err("Initialization failed: %d\n", err); - return err; + goto err_init; } err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0); if (err) { pr_err("Failed to register MTD device: %d\n", err); - return err; + goto err_dev_reg; } return 0; + +err_dev_reg: +err_init: + kfree(b47n); +out: + return err; } static int bcm47xxnflash_remove(struct platform_device *pdev) @@ -77,4 +85,22 @@ static struct platform_driver bcm47xxnflash_driver = { }, }; -module_platform_driver(bcm47xxnflash_driver); +static int __init bcm47xxnflash_init(void) +{ + int err; + + err = platform_driver_register(&bcm47xxnflash_driver); + if (err) + pr_err("Failed to register bcm47xx nand flash driver: %d\n", + err); + + return err; +} + +static void __exit bcm47xxnflash_exit(void) +{ + platform_driver_unregister(&bcm47xxnflash_driver); +} + +module_init(bcm47xxnflash_init); +module_exit(bcm47xxnflash_exit); diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 370b9dd..2ed2bb3 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1394,7 +1394,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { }; /* initialize driver data structures */ -static void denali_drv_init(struct denali_nand_info *denali) +void denali_drv_init(struct denali_nand_info *denali) { denali->idx = 0; @@ -1520,7 +1520,7 @@ int denali_init(struct denali_nand_info *denali) * so just let controller do 15bit ECC for MLC and 8bit ECC for * SLC if possible. * */ - if (!nand_is_slc(&denali->nand) && + if (denali->nand.cellinfo & NAND_CI_CELLTYPE_MSK && (denali->mtd.oobsize > (denali->bbtskipbytes + ECC_15BITS * (denali->mtd.writesize / ECC_SECTOR_SIZE)))) { diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 033f177..e3e4662 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -119,6 +119,7 @@ static void denali_pci_remove(struct pci_dev *dev) iounmap(denali->flash_mem); pci_release_regions(dev); pci_disable_device(dev); + pci_set_drvdata(dev, NULL); kfree(denali); } diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index b68a495..eaa3c29 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -38,7 +38,7 @@ #define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0 #endif -static unsigned long doc_locations[] __initdata = { +static unsigned long __initdata doc_locations[] = { #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 1b0265e..548db23 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -44,7 +44,6 @@ #include <linux/mtd/nand.h> #include <linux/bch.h> #include <linux/bitrev.h> -#include <linux/jiffies.h> /* * In "reliable mode" consecutive 2k pages are used in parallel (in some @@ -270,7 +269,7 @@ static int poll_status(struct docg4_priv *doc) */ uint16_t flash_status; - unsigned long timeo; + unsigned int timeo; void __iomem *docptr = doc->virtadr; dev_dbg(doc->dev, "%s...\n", __func__); @@ -278,18 +277,22 @@ static int poll_status(struct docg4_priv *doc) /* hardware quirk requires reading twice initially */ flash_status = readw(docptr + DOC_FLASHCONTROL); - timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */ + timeo = 1000; do { cpu_relax(); flash_status = readb(docptr + DOC_FLASHCONTROL); - } while (!(flash_status & DOC_CTRL_FLASHREADY) && - time_before(jiffies, timeo)); + } while (!(flash_status & DOC_CTRL_FLASHREADY) && --timeo); - if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) { + + if (!timeo) { dev_err(doc->dev, "%s: timed out!\n", __func__); return NAND_STATUS_FAIL; } + if (unlikely(timeo < 50)) + dev_warn(doc->dev, "%s: nearly timed out; %d remaining\n", + __func__, timeo); + return 0; } @@ -491,7 +494,7 @@ static uint8_t docg4_read_byte(struct mtd_info *mtd) return status; } - dev_warn(doc->dev, "unexpected call to read_byte()\n"); + dev_warn(doc->dev, "unexpectd call to read_byte()\n"); return 0; } @@ -1236,6 +1239,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd) nand->block_markbad = docg4_block_markbad; nand->read_buf = docg4_read_buf; nand->write_buf = docg4_write_buf16; + nand->scan_bbt = nand_default_bbt; nand->erase_cmd = docg4_erase_block; nand->ecc.read_page = docg4_read_page; nand->ecc.write_page = docg4_write_page; diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index c966fc7..2065720 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -28,7 +28,6 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/ioport.h> -#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -651,6 +650,8 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) chip->page_shift); dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", chip->phys_erase_shift); + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n", + chip->ecclayout); dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", chip->ecc.mode); dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 4335577..317a771 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -24,7 +24,6 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/of_address.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> @@ -136,69 +135,6 @@ static struct nand_ecclayout oob_4096_ecc8 = { .oobfree = { {2, 6}, {136, 82} }, }; -/* 8192-byte page size with 4-bit ECC */ -static struct nand_ecclayout oob_8192_ecc4 = { - .eccbytes = 128, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, - }, - .oobfree = { {2, 6}, {136, 208} }, -}; - -/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */ -static struct nand_ecclayout oob_8192_ecc8 = { - .eccbytes = 256, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, - }, - .oobfree = { {2, 6}, {264, 80} }, -}; /* * Generic flash bbt descriptors @@ -505,29 +441,20 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, if (mtd->writesize > 512) { nand_fcr0 = (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) | - (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT); + (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT); iowrite32be( - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT), - &ifc->ifc_nand.nand_fir0); - iowrite32be( - (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) | - (IFC_FIR_OP_RDSTAT << - IFC_NAND_FIR1_OP6_SHIFT) | - (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT), - &ifc->ifc_nand.nand_fir1); + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) | + (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT), + &ifc->ifc_nand.nand_fir0); } else { nand_fcr0 = ((NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT) | (NAND_CMD_SEQIN << - IFC_NAND_FCR0_CMD2_SHIFT) | - (NAND_CMD_STATUS << - IFC_NAND_FCR0_CMD3_SHIFT)); + IFC_NAND_FCR0_CMD2_SHIFT)); iowrite32be( (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | @@ -536,13 +463,8 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) | (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT), &ifc->ifc_nand.nand_fir0); - iowrite32be( - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) | - (IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) | - (IFC_FIR_OP_RDSTAT << - IFC_NAND_FIR1_OP7_SHIFT) | - (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT), - &ifc->ifc_nand.nand_fir1); + iowrite32be(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT, + &ifc->ifc_nand.nand_fir1); if (column >= mtd->writesize) nand_fcr0 |= @@ -796,6 +718,8 @@ static int fsl_ifc_chip_init_tail(struct mtd_info *mtd) chip->page_shift); dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__, chip->phys_erase_shift); + dev_dbg(priv->dev, "%s: nand->ecclayout = %p\n", __func__, + chip->ecclayout); dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__, chip->ecc.mode); dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__, @@ -948,25 +872,11 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) } else { layout = &oob_4096_ecc8; chip->ecc.bytes = 16; - chip->ecc.strength = 8; } priv->bufnum_mask = 1; break; - case CSOR_NAND_PGS_8K: - if ((csor & CSOR_NAND_ECC_MODE_MASK) == - CSOR_NAND_ECC_MODE_4) { - layout = &oob_8192_ecc4; - } else { - layout = &oob_8192_ecc8; - chip->ecc.bytes = 16; - chip->ecc.strength = 8; - } - - priv->bufnum_mask = 0; - break; - default: dev_err(priv->dev, "bad csor %#x: bad page size\n", csor); return -ENODEV; @@ -997,6 +907,7 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv) iounmap(priv->vbase); ifc_nand_ctrl->chips[priv->bank] = NULL; + dev_set_drvdata(priv->dev, NULL); return 0; } @@ -1171,7 +1082,25 @@ static struct platform_driver fsl_ifc_nand_driver = { .remove = fsl_ifc_nand_remove, }; -module_platform_driver(fsl_ifc_nand_driver); +static int __init fsl_ifc_nand_init(void) +{ + int ret; + + ret = platform_driver_register(&fsl_ifc_nand_driver); + if (ret) + printk(KERN_ERR "fsl-ifc: Failed to register platform" + "driver\n"); + + return ret; +} + +static void __exit fsl_ifc_nand_exit(void) +{ + platform_driver_unregister(&fsl_ifc_nand_driver); +} + +module_init(fsl_ifc_nand_init); +module_exit(fsl_ifc_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Freescale"); diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 4d203e8..04e0725 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -18,7 +18,6 @@ #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h> #include <linux/mtd/mtd.h> -#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/io.h> diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 8b27522..3dc1a75 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -573,6 +573,8 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len, dma_dev = chan->device; dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction); + flags |= DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP; + if (direction == DMA_TO_DEVICE) { dma_src = dma_addr; dma_dst = host->data_pa; diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index aaced29..4f8857f 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -187,12 +187,6 @@ int gpmi_init(struct gpmi_nand_data *this) /* Select BCH ECC. */ writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET); - /* - * Decouple the chip select from dma channel. We use dma0 for all - * the chips. - */ - writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET); - gpmi_disable_clk(this); return 0; err_out: @@ -1079,13 +1073,6 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) mask = MX23_BM_GPMI_DEBUG_READY0 << chip; reg = readl(r->gpmi_regs + HW_GPMI_DEBUG); } else if (GPMI_IS_MX28(this) || GPMI_IS_MX6Q(this)) { - /* - * In the imx6, all the ready/busy pins are bound - * together. So we only need to check chip 0. - */ - if (GPMI_IS_MX6Q(this)) - chip = 0; - /* MX28 shares the same R/B register as MX6Q. */ mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); reg = readl(r->gpmi_regs + HW_GPMI_STAT); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index dabbc14..a9830ff 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -45,10 +45,7 @@ static struct nand_bbt_descr gpmi_bbt_descr = { .pattern = scan_ff_pattern }; -/* - * We may change the layout if we can get the ECC info from the datasheet, - * else we will use all the (page + OOB). - */ +/* We will use all the (page + OOB). */ static struct nand_ecclayout gpmi_hw_ecclayout = { .eccbytes = 0, .eccpos = { 0, }, @@ -357,8 +354,9 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this) struct dma_chan *get_dma_chan(struct gpmi_nand_data *this) { - /* We use the DMA channel 0 to access all the nand chips. */ - return this->dma_chans[0]; + int chipnr = this->current_chip; + + return this->dma_chans[chipnr]; } /* Can we use the upper's buffer directly for DMA? */ @@ -394,6 +392,8 @@ static void dma_irq_callback(void *param) struct gpmi_nand_data *this = param; struct completion *dma_c = &this->dma_done; + complete(dma_c); + switch (this->dma_type) { case DMA_FOR_COMMAND: dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE); @@ -418,8 +418,6 @@ static void dma_irq_callback(void *param) default: pr_err("in wrong DMA operation.\n"); } - - complete(dma_c); } int start_dma_without_bch_irq(struct gpmi_nand_data *this, @@ -1265,22 +1263,14 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, static int gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) { - struct nand_oobfree *of = mtd->ecclayout->oobfree; - int status = 0; - - /* Do we have available oob area? */ - if (!of->length) - return -EPERM; - - if (!nand_is_slc(chip)) - return -EPERM; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of->offset, page); - chip->write_buf(mtd, chip->oob_poi + of->offset, of->length); - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - - status = chip->waitfunc(mtd, chip); - return status & NAND_STATUS_FAIL ? -EIO : 0; + /* + * The BCH will use all the (page + oob). + * Our gpmi_hw_ecclayout can only prohibit the JFFS2 to write the oob. + * But it can not stop some ioctls such MEMWRITEOOB which uses + * MTD_OPS_PLACE_OOB. So We have to implement this function to prohibit + * these ioctls too. + */ + return -EPERM; } static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) @@ -1578,6 +1568,8 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) { + int ret; + /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ if (GPMI_IS_MX23(this)) this->swap_block_mark = false; @@ -1585,8 +1577,12 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) this->swap_block_mark = true; /* Set up the medium geometry */ - return gpmi_set_geometry(this); + ret = gpmi_set_geometry(this); + if (ret) + return ret; + /* NAND boot init, depends on the gpmi_set_geometry(). */ + return nand_boot_init(this); } static void gpmi_nfc_exit(struct gpmi_nand_data *this) @@ -1668,7 +1664,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this) if (ret) goto err_out; - ret = nand_scan_ident(mtd, GPMI_IS_MX6Q(this) ? 2 : 1, NULL); + ret = nand_scan_ident(mtd, 1, NULL); if (ret) goto err_out; @@ -1676,16 +1672,10 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this) if (ret) goto err_out; - chip->options |= NAND_SKIP_BBTSCAN; ret = nand_scan_tail(mtd); if (ret) goto err_out; - ret = nand_boot_init(this); - if (ret) - goto err_out; - chip->scan_bbt(mtd); - ppdata.of_node = this->pdev->dev.of_node; ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (ret) @@ -1701,19 +1691,19 @@ static const struct platform_device_id gpmi_ids[] = { { .name = "imx23-gpmi-nand", .driver_data = IS_MX23, }, { .name = "imx28-gpmi-nand", .driver_data = IS_MX28, }, { .name = "imx6q-gpmi-nand", .driver_data = IS_MX6Q, }, - {} + {}, }; static const struct of_device_id gpmi_nand_id_table[] = { { .compatible = "fsl,imx23-gpmi-nand", - .data = (void *)&gpmi_ids[IS_MX23], + .data = (void *)&gpmi_ids[IS_MX23] }, { .compatible = "fsl,imx28-gpmi-nand", - .data = (void *)&gpmi_ids[IS_MX28], + .data = (void *)&gpmi_ids[IS_MX28] }, { .compatible = "fsl,imx6q-gpmi-nand", - .data = (void *)&gpmi_ids[IS_MX6Q], + .data = (void *)&gpmi_ids[IS_MX6Q] }, {} }; MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); @@ -1732,7 +1722,7 @@ static int gpmi_nand_probe(struct platform_device *pdev) return -ENODEV; } - this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL); + this = kzalloc(sizeof(*this), GFP_KERNEL); if (!this) { pr_err("Failed to allocate per-device memory\n"); return -ENOMEM; @@ -1762,6 +1752,7 @@ exit_nfc_init: release_resources(this); exit_acquire_resources: dev_err(this->dev, "driver registration failed: %d\n", ret); + kfree(this); return ret; } @@ -1772,6 +1763,7 @@ static int gpmi_nand_remove(struct platform_device *pdev) gpmi_nfc_exit(this); release_resources(this); + kfree(this); return 0; } diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h index 82114cd..53397cc 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h @@ -108,9 +108,6 @@ #define HW_GPMI_CTRL1_CLR 0x00000068 #define HW_GPMI_CTRL1_TOG 0x0000006c -#define BP_GPMI_CTRL1_DECOUPLE_CS 24 -#define BM_GPMI_CTRL1_DECOUPLE_CS (1 << BP_GPMI_CTRL1_DECOUPLE_CS) - #define BP_GPMI_CTRL1_WRN_DLY_SEL 22 #define BM_GPMI_CTRL1_WRN_DLY_SEL (0x3 << BP_GPMI_CTRL1_WRN_DLY_SEL) #define BF_GPMI_CTRL1_WRN_DLY_SEL(v) \ diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 327d96c..f4dd2a8 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -905,7 +905,7 @@ static struct platform_driver lpc32xx_nand_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, - .of_match_table = lpc32xx_nand_match, + .of_match_table = of_match_ptr(lpc32xx_nand_match), }, }; diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 23e6974..add7570 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -893,6 +893,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) /* Avoid extra scan if using BBT, setup BBT support */ if (host->ncfg->use_bbt) { + chip->options |= NAND_SKIP_BBTSCAN; chip->bbt_options |= NAND_BBT_USE_FLASH; /* @@ -914,6 +915,13 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) goto err_exit3; } + /* Standard layout in FLASH for bad block tables */ + if (host->ncfg->use_bbt) { + if (nand_default_bbt(mtd) < 0) + dev_err(&pdev->dev, + "Error initializing default bad block tables\n"); + } + mtd->name = "nxp_lpc3220_slc"; ppdata.of_node = pdev->dev.of_node; res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts, @@ -1015,7 +1023,7 @@ static struct platform_driver lpc32xx_nand_driver = { .driver = { .name = LPC32XX_MODNAME, .owner = THIS_MODULE, - .of_match_table = lpc32xx_nand_match, + .of_match_table = of_match_ptr(lpc32xx_nand_match), }, }; diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 439bc38..3c60a00 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -36,9 +36,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> -#include <linux/of_address.h> #include <linux/of_device.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/mpc5121.h> diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 9dfdb06..ce8242b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -32,7 +32,6 @@ #include <linux/io.h> #include <linux/irq.h> #include <linux/completion.h> -#include <linux/of.h> #include <linux/of_device.h> #include <linux/of_mtd.h> @@ -396,7 +395,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) if (useirq) { if (!host->devtype_data->check_int(host)) { - reinit_completion(&host->op_completion); + INIT_COMPLETION(host->op_completion); irq_control(host, 1); wait_for_completion(&host->op_completion); } @@ -1508,7 +1507,7 @@ static int mxcnd_probe(struct platform_device *pdev) host->devtype_data->irq_control(host, 0); err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq, - 0, DRIVER_NAME, host); + IRQF_DISABLED, DRIVER_NAME, host); if (err) return err; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bd39f7b..d340b2f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2912,13 +2912,12 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd, /* get the info we want. */ ecc = (struct onfi_ext_ecc_info *)cursor; - if (!ecc->codeword_size) { - pr_debug("Invalid codeword size\n"); - goto ext_out; + if (ecc->codeword_size) { + chip->ecc_strength_ds = ecc->ecc_bits; + chip->ecc_step_ds = 1 << ecc->codeword_size; } - chip->ecc_strength_ds = ecc->ecc_bits; - chip->ecc_step_ds = 1 << ecc->codeword_size; + pr_info("ONFI extended param page detected.\n"); ret = 0; ext_out: @@ -2936,34 +2935,29 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int i; int val; + /* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */ + if (chip->options & NAND_BUSWIDTH_16) { + pr_err("Trying ONFI probe in 16 bits mode, aborting !\n"); + return 0; + } /* Try ONFI for unknown chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') return 0; - /* - * ONFI must be probed in 8-bit mode or with NAND_BUSWIDTH_AUTO, not - * with NAND_BUSWIDTH_16 - */ - if (chip->options & NAND_BUSWIDTH_16) { - pr_err("ONFI cannot be probed in 16-bit mode; aborting\n"); - return 0; - } - chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { + pr_info("ONFI param page %d valid\n", i); break; } } - if (i == 3) { - pr_err("Could not find valid ONFI parameter page; aborting\n"); + if (i == 3) return 0; - } /* Check version */ val = le16_to_cpu(p->revision); @@ -2987,23 +2981,11 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, sanitize_string(p->model, sizeof(p->model)); if (!mtd->name) mtd->name = p->model; - mtd->writesize = le32_to_cpu(p->byte_per_page); - - /* - * pages_per_block and blocks_per_lun may not be a power-of-2 size - * (don't ask me who thought of this...). MTD assumes that these - * dimensions will be power-of-2, so just truncate the remaining area. - */ - mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); - mtd->erasesize *= mtd->writesize; - + mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); - - /* See erasesize comment */ - chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + chip->chipsize = le32_to_cpu(p->blocks_per_lun); chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; - chip->bits_per_cell = p->bits_per_cell; if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS) *busw = NAND_BUSWIDTH_16; @@ -3027,11 +3009,10 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, /* The Extended Parameter Page is supported since ONFI 2.1. */ if (nand_flash_detect_ext_param_page(mtd, chip, p)) - pr_warn("Failed to detect ONFI extended param page\n"); - } else { - pr_warn("Could not retrieve ONFI ECC requirements\n"); + pr_info("Failed to detect the extended param page.\n"); } + pr_info("ONFI flash detected\n"); return 1; } @@ -3094,16 +3075,6 @@ static int nand_id_len(u8 *id_data, int arrlen) return arrlen; } -/* Extract the bits of per cell from the 3rd byte of the extended ID */ -static int nand_get_bits_per_cell(u8 cellinfo) -{ - int bits; - - bits = cellinfo & NAND_CI_CELLTYPE_MSK; - bits >>= NAND_CI_CELLTYPE_SHIFT; - return bits + 1; -} - /* * Many new NAND share similar device ID codes, which represent the size of the * chip. The rest of the parameters must be decoded according to generic or @@ -3114,7 +3085,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, { int extid, id_len; /* The 3rd id byte holds MLC / multichip data */ - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); + chip->cellinfo = id_data[2]; /* The 4th id byte is the important one */ extid = id_data[3]; @@ -3130,7 +3101,8 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, * ID to decide what to do. */ if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG && - !nand_is_slc(chip) && id_data[5] != 0x00) { + (chip->cellinfo & NAND_CI_CELLTYPE_MSK) && + id_data[5] != 0x00) { /* Calc pagesize */ mtd->writesize = 2048 << (extid & 0x03); extid >>= 2; @@ -3162,7 +3134,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, (((extid >> 1) & 0x04) | (extid & 0x03)); *busw = 0; } else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX && - !nand_is_slc(chip)) { + (chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { unsigned int tmp; /* Calc pagesize */ @@ -3225,7 +3197,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, * - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC */ if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA && - nand_is_slc(chip) && + !(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (id_data[5] & 0x7) == 0x6 /* 24nm */ && !(id_data[4] & 0x80) /* !BENAND */) { mtd->oobsize = 32 * mtd->writesize >> 9; @@ -3250,9 +3222,6 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip, mtd->oobsize = mtd->writesize / 32; *busw = type->options & NAND_BUSWIDTH_16; - /* All legacy ID NAND are small-page, SLC */ - chip->bits_per_cell = 1; - /* * Check for Spansion/AMD ID + repeating 5th, 6th byte since * some Spansion chips have erasesize that conflicts with size @@ -3289,11 +3258,11 @@ static void nand_decode_bbm_options(struct mtd_info *mtd, * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba, * AMD/Spansion, and Macronix. All others scan only the first page. */ - if (!nand_is_slc(chip) && + if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (maf_id == NAND_MFR_SAMSUNG || maf_id == NAND_MFR_HYNIX)) chip->bbt_options |= NAND_BBT_SCANLASTPAGE; - else if ((nand_is_slc(chip) && + else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (maf_id == NAND_MFR_SAMSUNG || maf_id == NAND_MFR_HYNIX || maf_id == NAND_MFR_TOSHIBA || @@ -3317,7 +3286,7 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, mtd->erasesize = type->erasesize; mtd->oobsize = type->oobsize; - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); + chip->cellinfo = id_data[2]; chip->chipsize = (uint64_t)type->chipsize << 20; chip->options |= type->options; chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); @@ -3472,13 +3441,11 @@ ident_done: if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)\n", + pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," + " %dMiB, page size: %d, OOB size: %d\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, - chip->onfi_version ? chip->onfi_params.model : type->name); - - pr_info("NAND device: %dMiB, %s, page size: %d, OOB size: %d\n", - (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", - mtd->writesize, mtd->oobsize); + chip->onfi_version ? chip->onfi_params.model : type->name, + (int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize); return type; } @@ -3558,7 +3525,6 @@ int nand_scan_tail(struct mtd_info *mtd) { int i; struct nand_chip *chip = mtd->priv; - struct nand_ecc_ctrl *ecc = &chip->ecc; /* New bad blocks should be marked in OOB, flash-based BBT, or both */ BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && @@ -3575,19 +3541,19 @@ int nand_scan_tail(struct mtd_info *mtd) /* * If no default placement scheme is given, select an appropriate one. */ - if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) { + if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) { switch (mtd->oobsize) { case 8: - ecc->layout = &nand_oob_8; + chip->ecc.layout = &nand_oob_8; break; case 16: - ecc->layout = &nand_oob_16; + chip->ecc.layout = &nand_oob_16; break; case 64: - ecc->layout = &nand_oob_64; + chip->ecc.layout = &nand_oob_64; break; case 128: - ecc->layout = &nand_oob_128; + chip->ecc.layout = &nand_oob_128; break; default: pr_warn("No oob scheme defined for oobsize %d\n", @@ -3604,62 +3570,64 @@ int nand_scan_tail(struct mtd_info *mtd) * selected and we have 256 byte pagesize fallback to software ECC */ - switch (ecc->mode) { + switch (chip->ecc.mode) { case NAND_ECC_HW_OOB_FIRST: /* Similar to NAND_ECC_HW, but a separate read_page handle */ - if (!ecc->calculate || !ecc->correct || !ecc->hwctl) { + if (!chip->ecc.calculate || !chip->ecc.correct || + !chip->ecc.hwctl) { pr_warn("No ECC functions supplied; " "hardware ECC not possible\n"); BUG(); } - if (!ecc->read_page) - ecc->read_page = nand_read_page_hwecc_oob_first; + if (!chip->ecc.read_page) + chip->ecc.read_page = nand_read_page_hwecc_oob_first; case NAND_ECC_HW: /* Use standard hwecc read page function? */ - if (!ecc->read_page) - ecc->read_page = nand_read_page_hwecc; - if (!ecc->write_page) - ecc->write_page = nand_write_page_hwecc; - if (!ecc->read_page_raw) - ecc->read_page_raw = nand_read_page_raw; - if (!ecc->write_page_raw) - ecc->write_page_raw = nand_write_page_raw; - if (!ecc->read_oob) - ecc->read_oob = nand_read_oob_std; - if (!ecc->write_oob) - ecc->write_oob = nand_write_oob_std; - if (!ecc->read_subpage) - ecc->read_subpage = nand_read_subpage; - if (!ecc->write_subpage) - ecc->write_subpage = nand_write_subpage_hwecc; + if (!chip->ecc.read_page) + chip->ecc.read_page = nand_read_page_hwecc; + if (!chip->ecc.write_page) + chip->ecc.write_page = nand_write_page_hwecc; + if (!chip->ecc.read_page_raw) + chip->ecc.read_page_raw = nand_read_page_raw; + if (!chip->ecc.write_page_raw) + chip->ecc.write_page_raw = nand_write_page_raw; + if (!chip->ecc.read_oob) + chip->ecc.read_oob = nand_read_oob_std; + if (!chip->ecc.write_oob) + chip->ecc.write_oob = nand_write_oob_std; + if (!chip->ecc.read_subpage) + chip->ecc.read_subpage = nand_read_subpage; + if (!chip->ecc.write_subpage) + chip->ecc.write_subpage = nand_write_subpage_hwecc; case NAND_ECC_HW_SYNDROME: - if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) && - (!ecc->read_page || - ecc->read_page == nand_read_page_hwecc || - !ecc->write_page || - ecc->write_page == nand_write_page_hwecc)) { + if ((!chip->ecc.calculate || !chip->ecc.correct || + !chip->ecc.hwctl) && + (!chip->ecc.read_page || + chip->ecc.read_page == nand_read_page_hwecc || + !chip->ecc.write_page || + chip->ecc.write_page == nand_write_page_hwecc)) { pr_warn("No ECC functions supplied; " "hardware ECC not possible\n"); BUG(); } /* Use standard syndrome read/write page function? */ - if (!ecc->read_page) - ecc->read_page = nand_read_page_syndrome; - if (!ecc->write_page) - ecc->write_page = nand_write_page_syndrome; - if (!ecc->read_page_raw) - ecc->read_page_raw = nand_read_page_raw_syndrome; - if (!ecc->write_page_raw) - ecc->write_page_raw = nand_write_page_raw_syndrome; - if (!ecc->read_oob) - ecc->read_oob = nand_read_oob_syndrome; - if (!ecc->write_oob) - ecc->write_oob = nand_write_oob_syndrome; - - if (mtd->writesize >= ecc->size) { - if (!ecc->strength) { + if (!chip->ecc.read_page) + chip->ecc.read_page = nand_read_page_syndrome; + if (!chip->ecc.write_page) + chip->ecc.write_page = nand_write_page_syndrome; + if (!chip->ecc.read_page_raw) + chip->ecc.read_page_raw = nand_read_page_raw_syndrome; + if (!chip->ecc.write_page_raw) + chip->ecc.write_page_raw = nand_write_page_raw_syndrome; + if (!chip->ecc.read_oob) + chip->ecc.read_oob = nand_read_oob_syndrome; + if (!chip->ecc.write_oob) + chip->ecc.write_oob = nand_write_oob_syndrome; + + if (mtd->writesize >= chip->ecc.size) { + if (!chip->ecc.strength) { pr_warn("Driver must set ecc.strength when using hardware ECC\n"); BUG(); } @@ -3667,23 +3635,23 @@ int nand_scan_tail(struct mtd_info *mtd) } pr_warn("%d byte HW ECC not possible on " "%d byte page size, fallback to SW ECC\n", - ecc->size, mtd->writesize); - ecc->mode = NAND_ECC_SOFT; + chip->ecc.size, mtd->writesize); + chip->ecc.mode = NAND_ECC_SOFT; case NAND_ECC_SOFT: - ecc->calculate = nand_calculate_ecc; - ecc->correct = nand_correct_data; - ecc->read_page = nand_read_page_swecc; - ecc->read_subpage = nand_read_subpage; - ecc->write_page = nand_write_page_swecc; - ecc->read_page_raw = nand_read_page_raw; - ecc->write_page_raw = nand_write_page_raw; - ecc->read_oob = nand_read_oob_std; - ecc->write_oob = nand_write_oob_std; - if (!ecc->size) - ecc->size = 256; - ecc->bytes = 3; - ecc->strength = 1; + chip->ecc.calculate = nand_calculate_ecc; + chip->ecc.correct = nand_correct_data; + chip->ecc.read_page = nand_read_page_swecc; + chip->ecc.read_subpage = nand_read_subpage; + chip->ecc.write_page = nand_write_page_swecc; + chip->ecc.read_page_raw = nand_read_page_raw; + chip->ecc.write_page_raw = nand_write_page_raw; + chip->ecc.read_oob = nand_read_oob_std; + chip->ecc.write_oob = nand_write_oob_std; + if (!chip->ecc.size) + chip->ecc.size = 256; + chip->ecc.bytes = 3; + chip->ecc.strength = 1; break; case NAND_ECC_SOFT_BCH: @@ -3691,83 +3659,88 @@ int nand_scan_tail(struct mtd_info *mtd) pr_warn("CONFIG_MTD_ECC_BCH not enabled\n"); BUG(); } - ecc->calculate = nand_bch_calculate_ecc; - ecc->correct = nand_bch_correct_data; - ecc->read_page = nand_read_page_swecc; - ecc->read_subpage = nand_read_subpage; - ecc->write_page = nand_write_page_swecc; - ecc->read_page_raw = nand_read_page_raw; - ecc->write_page_raw = nand_write_page_raw; - ecc->read_oob = nand_read_oob_std; - ecc->write_oob = nand_write_oob_std; + chip->ecc.calculate = nand_bch_calculate_ecc; + chip->ecc.correct = nand_bch_correct_data; + chip->ecc.read_page = nand_read_page_swecc; + chip->ecc.read_subpage = nand_read_subpage; + chip->ecc.write_page = nand_write_page_swecc; + chip->ecc.read_page_raw = nand_read_page_raw; + chip->ecc.write_page_raw = nand_write_page_raw; + chip->ecc.read_oob = nand_read_oob_std; + chip->ecc.write_oob = nand_write_oob_std; /* * Board driver should supply ecc.size and ecc.bytes values to * select how many bits are correctable; see nand_bch_init() * for details. Otherwise, default to 4 bits for large page * devices. */ - if (!ecc->size && (mtd->oobsize >= 64)) { - ecc->size = 512; - ecc->bytes = 7; + if (!chip->ecc.size && (mtd->oobsize >= 64)) { + chip->ecc.size = 512; + chip->ecc.bytes = 7; } - ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes, - &ecc->layout); - if (!ecc->priv) { + chip->ecc.priv = nand_bch_init(mtd, + chip->ecc.size, + chip->ecc.bytes, + &chip->ecc.layout); + if (!chip->ecc.priv) { pr_warn("BCH ECC initialization failed!\n"); BUG(); } - ecc->strength = ecc->bytes * 8 / fls(8 * ecc->size); + chip->ecc.strength = + chip->ecc.bytes * 8 / fls(8 * chip->ecc.size); break; case NAND_ECC_NONE: pr_warn("NAND_ECC_NONE selected by board driver. " "This is not recommended!\n"); - ecc->read_page = nand_read_page_raw; - ecc->write_page = nand_write_page_raw; - ecc->read_oob = nand_read_oob_std; - ecc->read_page_raw = nand_read_page_raw; - ecc->write_page_raw = nand_write_page_raw; - ecc->write_oob = nand_write_oob_std; - ecc->size = mtd->writesize; - ecc->bytes = 0; - ecc->strength = 0; + chip->ecc.read_page = nand_read_page_raw; + chip->ecc.write_page = nand_write_page_raw; + chip->ecc.read_oob = nand_read_oob_std; + chip->ecc.read_page_raw = nand_read_page_raw; + chip->ecc.write_page_raw = nand_write_page_raw; + chip->ecc.write_oob = nand_write_oob_std; + chip->ecc.size = mtd->writesize; + chip->ecc.bytes = 0; + chip->ecc.strength = 0; break; default: - pr_warn("Invalid NAND_ECC_MODE %d\n", ecc->mode); + pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); BUG(); } /* For many systems, the standard OOB write also works for raw */ - if (!ecc->read_oob_raw) - ecc->read_oob_raw = ecc->read_oob; - if (!ecc->write_oob_raw) - ecc->write_oob_raw = ecc->write_oob; + if (!chip->ecc.read_oob_raw) + chip->ecc.read_oob_raw = chip->ecc.read_oob; + if (!chip->ecc.write_oob_raw) + chip->ecc.write_oob_raw = chip->ecc.write_oob; /* * The number of bytes available for a client to place data into * the out of band area. */ - ecc->layout->oobavail = 0; - for (i = 0; ecc->layout->oobfree[i].length - && i < ARRAY_SIZE(ecc->layout->oobfree); i++) - ecc->layout->oobavail += ecc->layout->oobfree[i].length; - mtd->oobavail = ecc->layout->oobavail; + chip->ecc.layout->oobavail = 0; + for (i = 0; chip->ecc.layout->oobfree[i].length + && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++) + chip->ecc.layout->oobavail += + chip->ecc.layout->oobfree[i].length; + mtd->oobavail = chip->ecc.layout->oobavail; /* * Set the number of read / write steps for one page depending on ECC * mode. */ - ecc->steps = mtd->writesize / ecc->size; - if (ecc->steps * ecc->size != mtd->writesize) { + chip->ecc.steps = mtd->writesize / chip->ecc.size; + if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { pr_warn("Invalid ECC parameters\n"); BUG(); } - ecc->total = ecc->steps * ecc->bytes; + chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */ - if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) { - switch (ecc->steps) { + if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && + !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { + switch (chip->ecc.steps) { case 2: mtd->subpage_sft = 1; break; @@ -3787,11 +3760,11 @@ int nand_scan_tail(struct mtd_info *mtd) chip->pagebuf = -1; /* Large page NAND with SOFT_ECC should support subpage reads */ - if ((ecc->mode == NAND_ECC_SOFT) && (chip->page_shift > 9)) + if ((chip->ecc.mode == NAND_ECC_SOFT) && (chip->page_shift > 9)) chip->options |= NAND_SUBPAGE_READ; /* Fill in remaining MTD driver data */ - mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH; + mtd->type = MTD_NANDFLASH; mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : MTD_CAP_NANDFLASH; mtd->_erase = nand_erase; @@ -3812,9 +3785,9 @@ int nand_scan_tail(struct mtd_info *mtd) mtd->writebufsize = mtd->writesize; /* propagate ecc info to mtd_info */ - mtd->ecclayout = ecc->layout; - mtd->ecc_strength = ecc->strength; - mtd->ecc_step_size = ecc->size; + mtd->ecclayout = chip->ecc.layout; + mtd->ecc_strength = chip->ecc.strength; + mtd->ecc_step_size = chip->ecc.size; /* * Initialize bitflip_threshold to its default prior scan_bbt() call. * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index c0615d1..bc06196 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -412,6 +412,25 @@ static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, } } +/* Scan a given block full */ +static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, + loff_t offs, uint8_t *buf, size_t readlen, + int scanlen, int numpages) +{ + int ret, j; + + ret = scan_read_oob(mtd, buf, offs, readlen); + /* Ignore ECC errors when checking for BBM */ + if (ret && !mtd_is_bitflip_or_eccerr(ret)) + return ret; + + for (j = 0; j < numpages; j++, buf += scanlen) { + if (check_pattern(buf, scanlen, mtd->writesize, bd)) + return 1; + } + return 0; +} + /* Scan a given block partially */ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, int numpages) @@ -458,17 +477,24 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) { struct nand_chip *this = mtd->priv; - int i, numblocks, numpages; + int i, numblocks, numpages, scanlen; int startblock; loff_t from; + size_t readlen; pr_info("Scanning device for bad blocks\n"); - if (bd->options & NAND_BBT_SCAN2NDPAGE) + if (bd->options & NAND_BBT_SCANALLPAGES) + numpages = 1 << (this->bbt_erase_shift - this->page_shift); + else if (bd->options & NAND_BBT_SCAN2NDPAGE) numpages = 2; else numpages = 1; + /* We need only read few bytes from the OOB area */ + scanlen = 0; + readlen = bd->len; + if (chip == -1) { numblocks = mtd->size >> this->bbt_erase_shift; startblock = 0; @@ -493,7 +519,12 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, BUG_ON(bd->options & NAND_BBT_NO_OOB); - ret = scan_block_fast(mtd, bd, from, buf, numpages); + if (bd->options & NAND_BBT_SCANALLPAGES) + ret = scan_block_full(mtd, bd, from, buf, readlen, + scanlen, numpages); + else + ret = scan_block_fast(mtd, bd, from, buf, numpages); + if (ret < 0) return ret; @@ -1361,3 +1392,4 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs) } EXPORT_SYMBOL(nand_scan_bbt); +EXPORT_SYMBOL(nand_default_bbt); diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 42e8a77..bdc1d15 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -575,7 +575,7 @@ static int alloc_device(struct nandsim *ns) cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600); if (IS_ERR(cfile)) return PTR_ERR(cfile); - if (!cfile->f_op->read && !cfile->f_op->aio_read) { + if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) { NS_ERR("alloc_device: cache file not readable\n"); err = -EINVAL; goto err_close; @@ -2372,7 +2372,7 @@ static int __init ns_init_module(void) if ((retval = init_nandsim(nsmtd)) != 0) goto err_exit; - if ((retval = chip->scan_bbt(nsmtd)) != 0) + if ((retval = nand_default_bbt(nsmtd)) != 0) goto err_exit; if ((retval = parse_badblocks(nand, nsmtd)) != 0) diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 69eaba6..8e148f1 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -30,7 +30,6 @@ #include <linux/mtd/ndfc.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> -#include <linux/of_address.h> #include <linux/of_platform.h> #include <asm/io.h> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f777250..4ecf0e5 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -25,8 +25,10 @@ #include <linux/of.h> #include <linux/of_device.h> -#include <linux/mtd/nand_bch.h> +#ifdef CONFIG_MTD_NAND_OMAP_BCH +#include <linux/bch.h> #include <linux/platform_data/elm.h> +#endif #include <linux/platform_data/mtd-nand-omap2.h> @@ -139,8 +141,6 @@ #define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */ #define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */ -#define BADBLOCK_MARKER_LENGTH 2 - #ifdef CONFIG_MTD_NAND_OMAP_BCH static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; @@ -149,6 +149,17 @@ static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; +/* Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks + */ +static uint8_t scan_ff_pattern[] = { 0xff }; +static struct nand_bbt_descr bb_descrip_flashbased = { + .options = NAND_BBT_SCANALLPAGES, + .offs = 0, + .len = 1, + .pattern = scan_ff_pattern, +}; + struct omap_nand_info { struct nand_hw_control controller; @@ -171,10 +182,14 @@ struct omap_nand_info { u_char *buf; int buf_len; struct gpmc_nand_regs reg; - /* fields specific for BCHx_HW ECC scheme */ + +#ifdef CONFIG_MTD_NAND_OMAP_BCH + struct bch_control *bch; + struct nand_ecclayout ecclayout; bool is_elm_used; struct device *elm_dev; struct device_node *of_node; +#endif }; /** @@ -1043,7 +1058,8 @@ static int omap_dev_ready(struct mtd_info *mtd) } } -#if defined(CONFIG_MTD_NAND_ECC_BCH) || defined(CONFIG_MTD_NAND_OMAP_BCH) +#ifdef CONFIG_MTD_NAND_OMAP_BCH + /** * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction * @mtd: MTD device structure @@ -1124,9 +1140,7 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) /* Clear ecc and enable bits */ writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); } -#endif -#ifdef CONFIG_MTD_NAND_ECC_BCH /** * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes * @mtd: MTD device structure @@ -1211,9 +1225,7 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat, return 0; } -#endif /* CONFIG_MTD_NAND_ECC_BCH */ -#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * omap3_calculate_ecc_bch - Generate bytes of ECC bytes * @mtd: MTD device structure @@ -1507,6 +1519,38 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, } /** + * omap3_correct_data_bch - Decode received data and correct errors + * @mtd: MTD device structure + * @data: page data + * @read_ecc: ecc read from nand flash + * @calc_ecc: ecc read from HW ECC registers + */ +static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data, + u_char *read_ecc, u_char *calc_ecc) +{ + int i, count; + /* cannot correct more than 8 errors */ + unsigned int errloc[8]; + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + + count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL, + errloc); + if (count > 0) { + /* correct errors */ + for (i = 0; i < count; i++) { + /* correct data only, not ecc bytes */ + if (errloc[i] < 8*512) + data[errloc[i]/8] ^= 1 << (errloc[i] & 7); + pr_debug("corrected bitflip %u\n", errloc[i]); + } + } else if (count < 0) { + pr_err("ecc unrecoverable error\n"); + } + return count; +} + +/** * omap_write_page_bch - BCH ecc based write page function for entire page * @mtd: mtd info structure * @chip: nand chip info structure @@ -1593,46 +1637,197 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, } /** - * is_elm_present - checks for presence of ELM module by scanning DT nodes - * @omap_nand_info: NAND device structure containing platform data - * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 + * omap3_free_bch - Release BCH ecc resources + * @mtd: MTD device structure */ -static int is_elm_present(struct omap_nand_info *info, - struct device_node *elm_node, enum bch_ecc bch_type) +static void omap3_free_bch(struct mtd_info *mtd) { - struct platform_device *pdev; - info->is_elm_used = false; - /* check whether elm-id is passed via DT */ - if (!elm_node) { - pr_err("nand: error: ELM DT node not found\n"); - return -ENODEV; + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + if (info->bch) { + free_bch(info->bch); + info->bch = NULL; } - pdev = of_find_device_by_node(elm_node); - /* check whether ELM device is registered */ - if (!pdev) { - pr_err("nand: error: ELM device not found\n"); - return -ENODEV; +} + +/** + * omap3_init_bch - Initialize BCH ECC + * @mtd: MTD device structure + * @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW) + */ +static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) +{ + int max_errors; + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); +#ifdef CONFIG_MTD_NAND_OMAP_BCH8 + const int hw_errors = BCH8_MAX_ERROR; +#else + const int hw_errors = BCH4_MAX_ERROR; +#endif + enum bch_ecc bch_type; + const __be32 *parp; + int lenp; + struct device_node *elm_node; + + info->bch = NULL; + + max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ? + BCH8_MAX_ERROR : BCH4_MAX_ERROR; + if (max_errors != hw_errors) { + pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported", + max_errors, hw_errors); + goto fail; } - /* ELM module available, now configure it */ - info->elm_dev = &pdev->dev; - if (elm_config(info->elm_dev, bch_type)) - return -ENODEV; - info->is_elm_used = true; + + info->nand.ecc.size = 512; + info->nand.ecc.hwctl = omap3_enable_hwecc_bch; + info->nand.ecc.mode = NAND_ECC_HW; + info->nand.ecc.strength = max_errors; + + if (hw_errors == BCH8_MAX_ERROR) + bch_type = BCH8_ECC; + else + bch_type = BCH4_ECC; + + /* Detect availability of ELM module */ + parp = of_get_property(info->of_node, "elm_id", &lenp); + if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) { + pr_err("Missing elm_id property, fall back to Software BCH\n"); + info->is_elm_used = false; + } else { + struct platform_device *pdev; + + elm_node = of_find_node_by_phandle(be32_to_cpup(parp)); + pdev = of_find_device_by_node(elm_node); + info->elm_dev = &pdev->dev; + + if (elm_config(info->elm_dev, bch_type) == 0) + info->is_elm_used = true; + } + + if (info->is_elm_used && (mtd->writesize <= 4096)) { + + if (hw_errors == BCH8_MAX_ERROR) + info->nand.ecc.bytes = BCH8_SIZE; + else + info->nand.ecc.bytes = BCH4_SIZE; + + info->nand.ecc.correct = omap_elm_correct_data; + info->nand.ecc.calculate = omap3_calculate_ecc_bch; + info->nand.ecc.read_page = omap_read_page_bch; + info->nand.ecc.write_page = omap_write_page_bch; + } else { + /* + * software bch library is only used to detect and + * locate errors + */ + info->bch = init_bch(13, max_errors, + 0x201b /* hw polynomial */); + if (!info->bch) + goto fail; + + info->nand.ecc.correct = omap3_correct_data_bch; + + /* + * The number of corrected errors in an ecc block that will + * trigger block scrubbing defaults to the ecc strength (4 or 8) + * Set mtd->bitflip_threshold here to define a custom threshold. + */ + + if (max_errors == 8) { + info->nand.ecc.bytes = 13; + info->nand.ecc.calculate = omap3_calculate_ecc_bch8; + } else { + info->nand.ecc.bytes = 7; + info->nand.ecc.calculate = omap3_calculate_ecc_bch4; + } + } + + pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors); + return 0; +fail: + omap3_free_bch(mtd); + return -1; +} + +/** + * omap3_init_bch_tail - Build an oob layout for BCH ECC correction. + * @mtd: MTD device structure + */ +static int omap3_init_bch_tail(struct mtd_info *mtd) +{ + int i, steps, offset; + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + struct nand_ecclayout *layout = &info->ecclayout; + + /* build oob layout */ + steps = mtd->writesize/info->nand.ecc.size; + layout->eccbytes = steps*info->nand.ecc.bytes; + + /* do not bother creating special oob layouts for small page devices */ + if (mtd->oobsize < 64) { + pr_err("BCH ecc is not supported on small page devices\n"); + goto fail; + } + + /* reserve 2 bytes for bad block marker */ + if (layout->eccbytes+2 > mtd->oobsize) { + pr_err("no oob layout available for oobsize %d eccbytes %u\n", + mtd->oobsize, layout->eccbytes); + goto fail; + } + + /* ECC layout compatible with RBL for BCH8 */ + if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE)) + offset = 2; + else + offset = mtd->oobsize - layout->eccbytes; + + /* put ecc bytes at oob tail */ + for (i = 0; i < layout->eccbytes; i++) + layout->eccpos[i] = offset + i; + + if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE)) + layout->oobfree[0].offset = 2 + layout->eccbytes * steps; + else + layout->oobfree[0].offset = 2; + + layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; + info->nand.ecc.layout = layout; + + if (!(info->nand.options & NAND_BUSWIDTH_16)) + info->nand.badblock_pattern = &bb_descrip_flashbased; return 0; +fail: + omap3_free_bch(mtd); + return -1; +} + +#else +static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) +{ + pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n"); + return -1; +} +static int omap3_init_bch_tail(struct mtd_info *mtd) +{ + return -1; +} +static void omap3_free_bch(struct mtd_info *mtd) +{ } -#endif /* CONFIG_MTD_NAND_ECC_BCH */ +#endif /* CONFIG_MTD_NAND_OMAP_BCH */ static int omap_nand_probe(struct platform_device *pdev) { struct omap_nand_info *info; struct omap_nand_platform_data *pdata; - struct mtd_info *mtd; - struct nand_chip *nand_chip; - struct nand_ecclayout *ecclayout; int err; - int i; - dma_cap_mask_t mask; - unsigned sig; + int i, offset; + dma_cap_mask_t mask; + unsigned sig; struct resource *res; struct mtd_part_parser_data ppdata = {}; @@ -1642,8 +1837,7 @@ static int omap_nand_probe(struct platform_device *pdev) return -ENODEV; } - info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info), - GFP_KERNEL); + info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL); if (!info) return -ENOMEM; @@ -1652,45 +1846,47 @@ static int omap_nand_probe(struct platform_device *pdev) spin_lock_init(&info->controller.lock); init_waitqueue_head(&info->controller.wq); - info->pdev = pdev; + info->pdev = pdev; + info->gpmc_cs = pdata->cs; info->reg = pdata->reg; + + info->mtd.priv = &info->nand; + info->mtd.name = dev_name(&pdev->dev); + info->mtd.owner = THIS_MODULE; + + info->nand.options = pdata->devsize; + info->nand.options |= NAND_SKIP_BBTSCAN; +#ifdef CONFIG_MTD_NAND_OMAP_BCH info->of_node = pdata->of_node; - mtd = &info->mtd; - mtd->priv = &info->nand; - mtd->name = dev_name(&pdev->dev); - mtd->owner = THIS_MODULE; - nand_chip = &info->nand; - nand_chip->ecc.priv = NULL; - nand_chip->options |= NAND_SKIP_BBTSCAN; +#endif res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { err = -EINVAL; dev_err(&pdev->dev, "error getting memory resource\n"); - goto return_error; + goto out_free_info; } info->phys_base = res->start; info->mem_size = resource_size(res); - if (!devm_request_mem_region(&pdev->dev, info->phys_base, - info->mem_size, pdev->dev.driver->name)) { + if (!request_mem_region(info->phys_base, info->mem_size, + pdev->dev.driver->name)) { err = -EBUSY; - goto return_error; + goto out_free_info; } - nand_chip->IO_ADDR_R = devm_ioremap(&pdev->dev, info->phys_base, - info->mem_size); - if (!nand_chip->IO_ADDR_R) { + info->nand.IO_ADDR_R = ioremap(info->phys_base, info->mem_size); + if (!info->nand.IO_ADDR_R) { err = -ENOMEM; - goto return_error; + goto out_release_mem_region; } - nand_chip->controller = &info->controller; + info->nand.controller = &info->controller; - nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R; - nand_chip->cmd_ctrl = omap_hwcontrol; + info->nand.IO_ADDR_W = info->nand.IO_ADDR_R; + info->nand.cmd_ctrl = omap_hwcontrol; /* * If RDY/BSY line is connected to OMAP then use the omap ready @@ -1700,42 +1896,26 @@ static int omap_nand_probe(struct platform_device *pdev) * device and read status register until you get a failure or success */ if (pdata->dev_ready) { - nand_chip->dev_ready = omap_dev_ready; - nand_chip->chip_delay = 0; + info->nand.dev_ready = omap_dev_ready; + info->nand.chip_delay = 0; } else { - nand_chip->waitfunc = omap_wait; - nand_chip->chip_delay = 50; + info->nand.waitfunc = omap_wait; + info->nand.chip_delay = 50; } - /* scan NAND device connected to chip controller */ - nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; - if (nand_scan_ident(mtd, 1, NULL)) { - pr_err("nand device scan failed, may be bus-width mismatch\n"); - err = -ENXIO; - goto return_error; - } - - /* check for small page devices */ - if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { - pr_err("small page devices are not supported\n"); - err = -EINVAL; - goto return_error; - } - - /* re-populate low-level callbacks based on xfer modes */ switch (pdata->xfer_type) { case NAND_OMAP_PREFETCH_POLLED: - nand_chip->read_buf = omap_read_buf_pref; - nand_chip->write_buf = omap_write_buf_pref; + info->nand.read_buf = omap_read_buf_pref; + info->nand.write_buf = omap_write_buf_pref; break; case NAND_OMAP_POLLED: - if (nand_chip->options & NAND_BUSWIDTH_16) { - nand_chip->read_buf = omap_read_buf16; - nand_chip->write_buf = omap_write_buf16; + if (info->nand.options & NAND_BUSWIDTH_16) { + info->nand.read_buf = omap_read_buf16; + info->nand.write_buf = omap_write_buf16; } else { - nand_chip->read_buf = omap_read_buf8; - nand_chip->write_buf = omap_write_buf8; + info->nand.read_buf = omap_read_buf8; + info->nand.write_buf = omap_write_buf8; } break; @@ -1747,7 +1927,7 @@ static int omap_nand_probe(struct platform_device *pdev) if (!info->dma) { dev_err(&pdev->dev, "DMA engine request failed\n"); err = -ENXIO; - goto return_error; + goto out_release_mem_region; } else { struct dma_slave_config cfg; @@ -1762,10 +1942,10 @@ static int omap_nand_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "DMA engine slave config failed: %d\n", err); - goto return_error; + goto out_release_mem_region; } - nand_chip->read_buf = omap_read_buf_dma_pref; - nand_chip->write_buf = omap_write_buf_dma_pref; + info->nand.read_buf = omap_read_buf_dma_pref; + info->nand.write_buf = omap_write_buf_dma_pref; } break; @@ -1774,36 +1954,34 @@ static int omap_nand_probe(struct platform_device *pdev) if (info->gpmc_irq_fifo <= 0) { dev_err(&pdev->dev, "error getting fifo irq\n"); err = -ENODEV; - goto return_error; + goto out_release_mem_region; } - err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo, - omap_nand_irq, IRQF_SHARED, - "gpmc-nand-fifo", info); + err = request_irq(info->gpmc_irq_fifo, omap_nand_irq, + IRQF_SHARED, "gpmc-nand-fifo", info); if (err) { dev_err(&pdev->dev, "requesting irq(%d) error:%d", info->gpmc_irq_fifo, err); info->gpmc_irq_fifo = 0; - goto return_error; + goto out_release_mem_region; } info->gpmc_irq_count = platform_get_irq(pdev, 1); if (info->gpmc_irq_count <= 0) { dev_err(&pdev->dev, "error getting count irq\n"); err = -ENODEV; - goto return_error; + goto out_release_mem_region; } - err = devm_request_irq(&pdev->dev, info->gpmc_irq_count, - omap_nand_irq, IRQF_SHARED, - "gpmc-nand-count", info); + err = request_irq(info->gpmc_irq_count, omap_nand_irq, + IRQF_SHARED, "gpmc-nand-count", info); if (err) { dev_err(&pdev->dev, "requesting irq(%d) error:%d", info->gpmc_irq_count, err); info->gpmc_irq_count = 0; - goto return_error; + goto out_release_mem_region; } - nand_chip->read_buf = omap_read_buf_irq_pref; - nand_chip->write_buf = omap_write_buf_irq_pref; + info->nand.read_buf = omap_read_buf_irq_pref; + info->nand.write_buf = omap_write_buf_irq_pref; break; @@ -1811,223 +1989,117 @@ static int omap_nand_probe(struct platform_device *pdev) dev_err(&pdev->dev, "xfer_type(%d) not supported!\n", pdata->xfer_type); err = -EINVAL; - goto return_error; + goto out_release_mem_region; } - /* populate MTD interface based on ECC scheme */ - nand_chip->ecc.layout = &omap_oobinfo; - ecclayout = &omap_oobinfo; - switch (pdata->ecc_opt) { - case OMAP_ECC_HAM1_CODE_HW: - pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n"); - nand_chip->ecc.mode = NAND_ECC_HW; - nand_chip->ecc.bytes = 3; - nand_chip->ecc.size = 512; - nand_chip->ecc.strength = 1; - nand_chip->ecc.calculate = omap_calculate_ecc; - nand_chip->ecc.hwctl = omap_enable_hwecc; - nand_chip->ecc.correct = omap_correct_data; - /* define ECC layout */ - ecclayout->eccbytes = nand_chip->ecc.bytes * - (mtd->writesize / - nand_chip->ecc.size); - if (nand_chip->options & NAND_BUSWIDTH_16) - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - else - ecclayout->eccpos[0] = 1; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; - break; - - case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH - pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); - nand_chip->ecc.mode = NAND_ECC_HW; - nand_chip->ecc.size = 512; - nand_chip->ecc.bytes = 7; - nand_chip->ecc.strength = 4; - nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; - nand_chip->ecc.correct = nand_bch_correct_data; - nand_chip->ecc.calculate = omap3_calculate_ecc_bch4; - /* define ECC layout */ - ecclayout->eccbytes = nand_chip->ecc.bytes * - (mtd->writesize / - nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; - /* software bch library is used for locating errors */ - nand_chip->ecc.priv = nand_bch_init(mtd, - nand_chip->ecc.size, - nand_chip->ecc.bytes, - &nand_chip->ecc.layout); - if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); + /* select the ecc type */ + if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT) + info->nand.ecc.mode = NAND_ECC_SOFT; + else if ((pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW) || + (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) { + info->nand.ecc.bytes = 3; + info->nand.ecc.size = 512; + info->nand.ecc.strength = 1; + info->nand.ecc.calculate = omap_calculate_ecc; + info->nand.ecc.hwctl = omap_enable_hwecc; + info->nand.ecc.correct = omap_correct_data; + info->nand.ecc.mode = NAND_ECC_HW; + } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || + (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { + err = omap3_init_bch(&info->mtd, pdata->ecc_opt); + if (err) { err = -EINVAL; + goto out_release_mem_region; } - break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif + } - case OMAP_ECC_BCH4_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH - pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); - nand_chip->ecc.mode = NAND_ECC_HW; - nand_chip->ecc.size = 512; - /* 14th bit is kept reserved for ROM-code compatibility */ - nand_chip->ecc.bytes = 7 + 1; - nand_chip->ecc.strength = 4; - nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; - nand_chip->ecc.correct = omap_elm_correct_data; - nand_chip->ecc.calculate = omap3_calculate_ecc_bch; - nand_chip->ecc.read_page = omap_read_page_bch; - nand_chip->ecc.write_page = omap_write_page_bch; - /* define ECC layout */ - ecclayout->eccbytes = nand_chip->ecc.bytes * - (mtd->writesize / - nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; - /* This ECC scheme requires ELM H/W block */ - if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { - pr_err("nand: error: could not initialize ELM\n"); - err = -ENODEV; - goto return_error; + /* DIP switches on some boards change between 8 and 16 bit + * bus widths for flash. Try the other width if the first try fails. + */ + if (nand_scan_ident(&info->mtd, 1, NULL)) { + info->nand.options ^= NAND_BUSWIDTH_16; + if (nand_scan_ident(&info->mtd, 1, NULL)) { + err = -ENXIO; + goto out_release_mem_region; } - break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif + } - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH - pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); - nand_chip->ecc.mode = NAND_ECC_HW; - nand_chip->ecc.size = 512; - nand_chip->ecc.bytes = 13; - nand_chip->ecc.strength = 8; - nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; - nand_chip->ecc.correct = nand_bch_correct_data; - nand_chip->ecc.calculate = omap3_calculate_ecc_bch8; - /* define ECC layout */ - ecclayout->eccbytes = nand_chip->ecc.bytes * - (mtd->writesize / - nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; - /* software bch library is used for locating errors */ - nand_chip->ecc.priv = nand_bch_init(mtd, - nand_chip->ecc.size, - nand_chip->ecc.bytes, - &nand_chip->ecc.layout); - if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); - err = -EINVAL; - goto return_error; - } - break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif + /* rom code layout */ + if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) { - case OMAP_ECC_BCH8_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH - pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); - nand_chip->ecc.mode = NAND_ECC_HW; - nand_chip->ecc.size = 512; - /* 14th bit is kept reserved for ROM-code compatibility */ - nand_chip->ecc.bytes = 13 + 1; - nand_chip->ecc.strength = 8; - nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; - nand_chip->ecc.correct = omap_elm_correct_data; - nand_chip->ecc.calculate = omap3_calculate_ecc_bch; - nand_chip->ecc.read_page = omap_read_page_bch; - nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); - if (err < 0) { - pr_err("nand: error: could not initialize ELM\n"); - goto return_error; + if (info->nand.options & NAND_BUSWIDTH_16) + offset = 2; + else { + offset = 1; + info->nand.badblock_pattern = &bb_descrip_flashbased; + } + omap_oobinfo.eccbytes = 3 * (info->mtd.oobsize/16); + for (i = 0; i < omap_oobinfo.eccbytes; i++) + omap_oobinfo.eccpos[i] = i+offset; + + omap_oobinfo.oobfree->offset = offset + omap_oobinfo.eccbytes; + omap_oobinfo.oobfree->length = info->mtd.oobsize - + (offset + omap_oobinfo.eccbytes); + + info->nand.ecc.layout = &omap_oobinfo; + } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || + (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { + /* build OOB layout for BCH ECC correction */ + err = omap3_init_bch_tail(&info->mtd); + if (err) { + err = -EINVAL; + goto out_release_mem_region; } - /* define ECC layout */ - ecclayout->eccbytes = nand_chip->ecc.bytes * - (mtd->writesize / - nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; - break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif - - default: - pr_err("nand: error: invalid or unsupported ECC scheme\n"); - err = -EINVAL; - goto return_error; - } - - /* populate remaining ECC layout data */ - ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH + - ecclayout->eccbytes); - for (i = 1; i < ecclayout->eccbytes; i++) - ecclayout->eccpos[i] = ecclayout->eccpos[0] + i; - /* check if NAND device's OOB is enough to store ECC signatures */ - if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { - pr_err("not enough OOB bytes required = %d, available=%d\n", - ecclayout->eccbytes, mtd->oobsize); - err = -EINVAL; - goto return_error; } /* second phase scan */ - if (nand_scan_tail(mtd)) { + if (nand_scan_tail(&info->mtd)) { err = -ENXIO; - goto return_error; + goto out_release_mem_region; } ppdata.of_node = pdata->of_node; - mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts, + mtd_device_parse_register(&info->mtd, NULL, &ppdata, pdata->parts, pdata->nr_parts); - platform_set_drvdata(pdev, mtd); + platform_set_drvdata(pdev, &info->mtd); return 0; -return_error: +out_release_mem_region: if (info->dma) dma_release_channel(info->dma); - if (nand_chip->ecc.priv) { - nand_bch_free(nand_chip->ecc.priv); - nand_chip->ecc.priv = NULL; - } + if (info->gpmc_irq_count > 0) + free_irq(info->gpmc_irq_count, info); + if (info->gpmc_irq_fifo > 0) + free_irq(info->gpmc_irq_fifo, info); + release_mem_region(info->phys_base, info->mem_size); +out_free_info: + kfree(info); + return err; } static int omap_nand_remove(struct platform_device *pdev) { struct mtd_info *mtd = platform_get_drvdata(pdev); - struct nand_chip *nand_chip = mtd->priv; struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - if (nand_chip->ecc.priv) { - nand_bch_free(nand_chip->ecc.priv); - nand_chip->ecc.priv = NULL; - } + omap3_free_bch(&info->mtd); + if (info->dma) dma_release_channel(info->dma); - nand_release(mtd); + + if (info->gpmc_irq_count > 0) + free_irq(info->gpmc_irq_count, info); + if (info->gpmc_irq_fifo > 0) + free_irq(info->gpmc_irq_fifo, info); + + /* Release NAND device, its internal structures and partitions */ + nand_release(&info->mtd); + iounmap(info->nand.IO_ADDR_R); + release_mem_region(info->phys_base, info->mem_size); + kfree(info); return 0; } diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 4d17436..5a67082 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -28,8 +28,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/nand_ecc.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pci.h> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4cabdc9..c28d4e2 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -39,13 +39,6 @@ #define NAND_STOP_DELAY (2 * HZ/50) #define PAGE_CHUNK_SIZE (2048) -/* - * Define a buffer size for the initial command that detects the flash device: - * STATUS, READID and PARAM. The largest of these is the PARAM command, - * needing 256 bytes. - */ -#define INIT_BUFFER_SIZE 256 - /* registers and bit definitions */ #define NDCR (0x00) /* Control register */ #define NDTR0CS0 (0x04) /* Timing Parameter 0 for CS0 */ @@ -171,7 +164,6 @@ struct pxa3xx_nand_info { unsigned int buf_start; unsigned int buf_count; - unsigned int buf_size; /* DMA information */ int drcmr_dat; @@ -548,6 +540,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->oob_size = 0; info->use_ecc = 0; info->use_spare = 1; + info->use_dma = (use_dma) ? 1 : 0; info->is_ready = 0; info->retcode = ERR_NONE; if (info->cs != 0) @@ -919,20 +912,26 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) return 0; } +/* the maximum possible buffer size for large page with OOB data + * is: 2048 + 64 = 2112 bytes, allocate a page here for both the + * data buffer and the DMA descriptor + */ +#define MAX_BUFF_SIZE PAGE_SIZE + #ifdef ARCH_HAS_DMA static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) { struct platform_device *pdev = info->pdev; - int data_desc_offset = info->buf_size - sizeof(struct pxa_dma_desc); + int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc); if (use_dma == 0) { - info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); + info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL); if (info->data_buff == NULL) return -ENOMEM; return 0; } - info->data_buff = dma_alloc_coherent(&pdev->dev, info->buf_size, + info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE, &info->data_buff_phys, GFP_KERNEL); if (info->data_buff == NULL) { dev_err(&pdev->dev, "failed to allocate dma buffer\n"); @@ -946,16 +945,11 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) pxa3xx_nand_data_dma_irq, info); if (info->data_dma_ch < 0) { dev_err(&pdev->dev, "failed to request data dma\n"); - dma_free_coherent(&pdev->dev, info->buf_size, + dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); return info->data_dma_ch; } - /* - * Now that DMA buffers are allocated we turn on - * DMA proper for I/O operations. - */ - info->use_dma = 1; return 0; } @@ -964,7 +958,7 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info) struct platform_device *pdev = info->pdev; if (use_dma) { pxa_free_dma(info->data_dma_ch); - dma_free_coherent(&pdev->dev, info->buf_size, + dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); } else { kfree(info->data_buff); @@ -973,7 +967,7 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info) #else static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) { - info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); + info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL); if (info->data_buff == NULL) return -ENOMEM; return 0; @@ -1087,16 +1081,7 @@ KEEP_CONFIG: else host->col_addr_cycles = 1; - /* release the initial buffer */ - kfree(info->data_buff); - - /* allocate the real data + oob buffer */ - info->buf_size = mtd->writesize + mtd->oobsize; - ret = pxa3xx_nand_init_buff(info); - if (ret) - return ret; info->oob_buff = info->data_buff + mtd->writesize; - if ((mtd->size >> chip->page_shift) > 65536) host->row_addr_cycles = 3; else @@ -1202,18 +1187,15 @@ static int alloc_nand_resource(struct platform_device *pdev) } info->mmio_phys = r->start; - /* Allocate a buffer to allow flash detection */ - info->buf_size = INIT_BUFFER_SIZE; - info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); - if (info->data_buff == NULL) { - ret = -ENOMEM; + ret = pxa3xx_nand_init_buff(info); + if (ret) goto fail_disable_clk; - } /* initialize all interrupts to be disabled */ disable_int(info, NDSR_MASK); - ret = request_irq(irq, pxa3xx_nand_irq, 0, pdev->name, info); + ret = request_irq(irq, pxa3xx_nand_irq, IRQF_DISABLED, + pdev->name, info); if (ret < 0) { dev_err(&pdev->dev, "failed to request IRQ\n"); goto fail_free_buf; @@ -1225,7 +1207,7 @@ static int alloc_nand_resource(struct platform_device *pdev) fail_free_buf: free_irq(irq, info); - kfree(info->data_buff); + pxa3xx_nand_free_buff(info); fail_disable_clk: clk_disable_unprepare(info->clk); return ret; @@ -1430,7 +1412,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) static struct platform_driver pxa3xx_nand_driver = { .driver = { .name = "pxa3xx-nand", - .of_match_table = pxa3xx_nand_dt_ids, + .of_match_table = of_match_ptr(pxa3xx_nand_dt_ids), }, .probe = pxa3xx_nand_probe, .remove = pxa3xx_nand_remove, diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 325930d..9dcf02d 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -181,7 +181,7 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read) /* Set dma direction */ dev->dma_dir = do_read; dev->dma_stage = 1; - reinit_completion(&dev->dma_done); + INIT_COMPLETION(dev->dma_done); dbg_verbose("doing dma %s ", do_read ? "read" : "write"); diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index fe8058a..09dde7d 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -15,7 +15,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> -#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/io.h> @@ -150,13 +149,17 @@ static int socrates_nand_probe(struct platform_device *ofdev) struct mtd_part_parser_data ppdata; /* Allocate memory for the device structure (and zero it) */ - host = devm_kzalloc(&ofdev->dev, sizeof(*host), GFP_KERNEL); - if (!host) + host = kzalloc(sizeof(struct socrates_nand_host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR + "socrates_nand: failed to allocate device structure.\n"); return -ENOMEM; + } host->io_base = of_iomap(ofdev->dev.of_node, 0); if (host->io_base == NULL) { - dev_err(&ofdev->dev, "ioremap failed\n"); + printk(KERN_ERR "socrates_nand: ioremap failed\n"); + kfree(host); return -EIO; } @@ -208,7 +211,9 @@ static int socrates_nand_probe(struct platform_device *ofdev) nand_release(mtd); out: + dev_set_drvdata(&ofdev->dev, NULL); iounmap(host->io_base); + kfree(host); return res; } @@ -222,7 +227,9 @@ static int socrates_nand_remove(struct platform_device *ofdev) nand_release(mtd); + dev_set_drvdata(&ofdev->dev, NULL); iounmap(host->io_base); + kfree(host); return 0; } diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index a3747c9..396530d 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -428,7 +428,8 @@ static int tmio_probe(struct platform_device *dev) /* 15 us command delay time */ nand_chip->chip_delay = 15; - retval = request_irq(irq, &tmio_irq, 0, dev_name(&dev->dev), tmio); + retval = request_irq(irq, &tmio_irq, + IRQF_DISABLED, dev_name(&dev->dev), tmio); if (retval) { dev_err(&dev->dev, "request_irq error %d\n", retval); goto err_irq; diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 46f27de..c5f4ebf 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -50,7 +50,7 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) struct NFTLrecord *nftl; unsigned long temp; - if (!mtd_type_is_nand(mtd) || mtd->size > UINT_MAX) + if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX) return; /* OK, this is moderately ugly. But probably safe. Alternatives? */ if (memcmp(mtd->name, "DiskOnChip", 10)) diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 6547c84..558071b 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -159,7 +159,7 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state) syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); } - reinit_completion(&c->irq_done); + INIT_COMPLETION(c->irq_done); if (c->gpio_irq) { result = gpio_get_value(c->gpio_irq); if (result == -1) { @@ -349,7 +349,7 @@ static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area, omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); - reinit_completion(&c->dma_done); + INIT_COMPLETION(c->dma_done); omap_start_dma(c->dma_channel); timeout = jiffies + msecs_to_jiffies(20); @@ -420,7 +420,7 @@ static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area, omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); - reinit_completion(&c->dma_done); + INIT_COMPLETION(c->dma_done); omap_start_dma(c->dma_channel); timeout = jiffies + msecs_to_jiffies(20); @@ -499,7 +499,7 @@ static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); - reinit_completion(&c->dma_done); + INIT_COMPLETION(c->dma_done); omap_start_dma(c->dma_channel); wait_for_completion(&c->dma_done); @@ -544,7 +544,7 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); - reinit_completion(&c->dma_done); + INIT_COMPLETION(c->dma_done); omap_start_dma(c->dma_channel); wait_for_completion(&c->dma_done); @@ -573,6 +573,28 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, static struct platform_driver omap2_onenand_driver; +static int __adjust_timing(struct device *dev, void *data) +{ + int ret = 0; + struct omap2_onenand *c; + + c = dev_get_drvdata(dev); + + BUG_ON(c->setup == NULL); + + /* DMA is not in use so this is all that is needed */ + /* Revisit for OMAP3! */ + ret = c->setup(c->onenand.base, &c->freq); + + return ret; +} + +int omap2_onenand_rephase(void) +{ + return driver_for_each_device(&omap2_onenand_driver.driver, NULL, + NULL, __adjust_timing); +} + static void omap2_onenand_shutdown(struct platform_device *pdev) { struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 1de33b5..b3f41f2 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -2556,6 +2556,10 @@ static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) { int ret; + /* Check for invalid offset */ + if (ofs > mtd->size) + return -EINVAL; + onenand_get_device(mtd, FL_READING); ret = onenand_block_isbad_nolock(mtd, ofs, 0); onenand_release_device(mtd); @@ -3525,7 +3529,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; unsigned die, bdry; - int syscfg, locked; + int ret, syscfg, locked; /* Disable ECC */ syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1); @@ -3536,7 +3540,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd) this->wait(mtd, FL_SYNCING); this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0); - this->wait(mtd, FL_READING); + ret = this->wait(mtd, FL_READING); bdry = this->read_word(this->base + ONENAND_DATARAM); if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3) @@ -3546,7 +3550,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd) this->boundary[die] = bdry & FLEXONENAND_PI_MASK; this->command(mtd, ONENAND_CMD_RESET, 0, 0); - this->wait(mtd, FL_RESETING); + ret = this->wait(mtd, FL_RESETING); printk(KERN_INFO "Die %d boundary: %d%s\n", die, this->boundary[die], locked ? "(Locked)" : "(Unlocked)"); @@ -3730,7 +3734,7 @@ static int flexonenand_set_boundary(struct mtd_info *mtd, int die, /* Check is boundary is locked */ this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0); - this->wait(mtd, FL_READING); + ret = this->wait(mtd, FL_READING); thisboundary = this->read_word(this->base + ONENAND_DATARAM); if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) { @@ -3831,7 +3835,7 @@ static int onenand_chip_probe(struct mtd_info *mtd) static int onenand_probe(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; - int dev_id, ver_id; + int maf_id, dev_id, ver_id; int density; int ret; @@ -3839,7 +3843,8 @@ static int onenand_probe(struct mtd_info *mtd) if (ret) return ret; - /* Device and version IDs from Register */ + /* Read manufacturer and device IDs from Register */ + maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY); diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index daf82ba..ab2a52a 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -290,7 +290,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) int cis_sector; /* Check for small page NAND flash */ - if (!mtd_type_is_nand(mtd) || mtd->oobsize != OOB_SIZE || + if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE || mtd->size > UINT_MAX) return; diff --git a/drivers/mtd/tests/nandbiterrs.c b/drivers/mtd/tests/nandbiterrs.c index 6f97615..3cd3aab 100644 --- a/drivers/mtd/tests/nandbiterrs.c +++ b/drivers/mtd/tests/nandbiterrs.c @@ -349,7 +349,7 @@ static int __init mtd_nandbiterrs_init(void) goto exit_mtddev; } - if (!mtd_type_is_nand(mtd)) { + if (mtd->type != MTD_NANDFLASH) { pr_info("this test requires NAND flash\n"); err = -ENODEV; goto exit_nand; diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 2e9e2d1..ff35c46 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -289,7 +289,7 @@ static int __init mtd_oobtest_init(void) return err; } - if (!mtd_type_is_nand(mtd)) { + if (mtd->type != MTD_NANDFLASH) { pr_info("this test requires NAND flash\n"); goto out; } diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c index ed2d3f6..44b96e9 100644 --- a/drivers/mtd/tests/pagetest.c +++ b/drivers/mtd/tests/pagetest.c @@ -353,7 +353,7 @@ static int __init mtd_pagetest_init(void) return err; } - if (!mtd_type_is_nand(mtd)) { + if (mtd->type != MTD_NANDFLASH) { pr_info("this test requires NAND flash\n"); goto out; } diff --git a/drivers/mtd/tests/subpagetest.c b/drivers/mtd/tests/subpagetest.c index a876371..e2c0adf 100644 --- a/drivers/mtd/tests/subpagetest.c +++ b/drivers/mtd/tests/subpagetest.c @@ -299,7 +299,7 @@ static int __init mtd_subpagetest_init(void) return err; } - if (!mtd_type_is_nand(mtd)) { + if (mtd->type != MTD_NANDFLASH) { pr_info("this test requires NAND flash\n"); goto out; } diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index 33bb1f2..c071d41 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -900,9 +900,10 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, * number. */ image_seq = be32_to_cpu(ech->image_seq); - if (!ubi->image_seq) + if (!ubi->image_seq && image_seq) ubi->image_seq = image_seq; - if (image_seq && ubi->image_seq != image_seq) { + if (ubi->image_seq && image_seq && + ubi->image_seq != image_seq) { ubi_err("bad image sequence number %d in PEB %d, expected %d", image_seq, pnum, ubi->image_seq); ubi_dump_ec_hdr(ech); @@ -1416,11 +1417,9 @@ int ubi_attach(struct ubi_device *ubi, int force_scan) ai = alloc_ai("ubi_aeb_slab_cache2"); if (!ai) return -ENOMEM; - - err = scan_all(ubi, ai, 0); - } else { - err = scan_all(ubi, ai, UBI_FM_MAX_START); } + + err = scan_all(ubi, ai, UBI_FM_MAX_START); } } #else diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index e05dc62..315dcc6 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -41,7 +41,6 @@ #include <linux/kthread.h> #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/major.h> #include "ubi.h" /* Maximum length of the 'mtd=' parameter */ diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index ead8613..f5aa4b0 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -407,7 +407,6 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, */ for (i = 0; i < pool_size; i++) { int scrub = 0; - int image_seq; pnum = be32_to_cpu(pebs[i]); @@ -426,16 +425,10 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, } else if (ret == UBI_IO_BITFLIPS) scrub = 1; - /* - * Older UBI implementations have image_seq set to zero, so - * we shouldn't fail if image_seq == 0. - */ - image_seq = be32_to_cpu(ech->image_seq); - - if (image_seq && (image_seq != ubi->image_seq)) { + if (be32_to_cpu(ech->image_seq) != ubi->image_seq) { ubi_err("bad image seq: 0x%x, expected: 0x%x", be32_to_cpu(ech->image_seq), ubi->image_seq); - ret = UBI_BAD_FASTMAP; + err = UBI_BAD_FASTMAP; goto out; } @@ -826,10 +819,6 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) list_move_tail(&tmp_aeb->u.list, &ai->free); - ubi_assert(list_empty(&used)); - ubi_assert(list_empty(&eba_orphans)); - ubi_assert(list_empty(&free)); - /* * If fastmap is leaking PEBs (must not happen), raise a * fat warning and fall back to scanning mode. @@ -845,19 +834,6 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, fail_bad: ret = UBI_BAD_FASTMAP; fail: - list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) { - kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); - list_del(&tmp_aeb->u.list); - } - list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &eba_orphans, u.list) { - kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); - list_del(&tmp_aeb->u.list); - } - list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) { - kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); - list_del(&tmp_aeb->u.list); - } - return ret; } @@ -947,8 +923,6 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, } for (i = 0; i < used_blocks; i++) { - int image_seq; - pnum = be32_to_cpu(fmsb->block_loc[i]); if (ubi_io_is_bad(ubi, pnum)) { @@ -966,17 +940,10 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, } else if (ret == UBI_IO_BITFLIPS) fm->to_be_tortured[i] = 1; - image_seq = be32_to_cpu(ech->image_seq); if (!ubi->image_seq) - ubi->image_seq = image_seq; + ubi->image_seq = be32_to_cpu(ech->image_seq); - /* - * Older UBI implementations have image_seq set to zero, so - * we shouldn't fail if image_seq == 0. - */ - if (image_seq && (image_seq != ubi->image_seq)) { - ubi_err("wrong image seq:%d instead of %d", - be32_to_cpu(ech->image_seq), ubi->image_seq); + if (be32_to_cpu(ech->image_seq) != ubi->image_seq) { ret = UBI_BAD_FASTMAP; goto free_hdr; } diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 02317c1..c95bfb1 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -599,6 +599,10 @@ static void refill_wl_user_pool(struct ubi_device *ubi) return_unused_pool_pebs(ubi, pool); for (pool->size = 0; pool->size < pool->max_size; pool->size++) { + if (!ubi->free.rb_node || + (ubi->free_count - ubi->beb_rsvd_pebs < 1)) + break; + pool->pebs[pool->size] = __wl_get_peb(ubi); if (pool->pebs[pool->size] < 0) break; |