diff options
Diffstat (limited to 'drivers/mtd')
54 files changed, 1600 insertions, 708 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5a2d71729b9a..2a8ac6829d42 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -1,6 +1,5 @@ menuconfig MTD tristate "Memory Technology Device (MTD) support" - depends on GENERIC_IO help Memory Technology Devices are flash, RAM and similar chips, often used for solid state file systems on embedded devices. This option diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c index afb43d5e1782..1cd0fff0e940 100644 --- a/drivers/mtd/chips/map_ram.c +++ b/drivers/mtd/chips/map_ram.c @@ -20,8 +20,9 @@ static int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_ch static int mapram_erase (struct mtd_info *, struct erase_info *); static void mapram_nop (struct mtd_info *); static struct mtd_info *map_ram_probe(struct map_info *map); -static unsigned long mapram_unmapped_area(struct mtd_info *, unsigned long, - unsigned long, unsigned long); +static int mapram_point (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, void **virt, resource_size_t *phys); +static int mapram_unpoint(struct mtd_info *mtd, loff_t from, size_t len); static struct mtd_chip_driver mapram_chipdrv = { @@ -65,11 +66,12 @@ static struct mtd_info *map_ram_probe(struct map_info *map) mtd->type = MTD_RAM; mtd->size = map->size; mtd->_erase = mapram_erase; - mtd->_get_unmapped_area = mapram_unmapped_area; mtd->_read = mapram_read; mtd->_write = mapram_write; mtd->_panic_write = mapram_write; + mtd->_point = mapram_point; mtd->_sync = mapram_nop; + mtd->_unpoint = mapram_unpoint; mtd->flags = MTD_CAP_RAM; mtd->writesize = 1; @@ -81,19 +83,23 @@ static struct mtd_info *map_ram_probe(struct map_info *map) return mtd; } - -/* - * Allow NOMMU mmap() to directly map the device (if not NULL) - * - return the address to which the offset maps - * - return -ENOSYS to indicate refusal to do the mapping - */ -static unsigned long mapram_unmapped_area(struct mtd_info *mtd, - unsigned long len, - unsigned long offset, - unsigned long flags) +static int mapram_point(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, void **virt, resource_size_t *phys) { struct map_info *map = mtd->priv; - return (unsigned long) map->virt + offset; + + if (!map->virt) + return -EINVAL; + *virt = map->virt + from; + if (phys) + *phys = map->phys + from; + *retlen = len; + return 0; +} + +static int mapram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) +{ + return 0; } static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c index e67f73ab44c9..20e3604b4d71 100644 --- a/drivers/mtd/chips/map_rom.c +++ b/drivers/mtd/chips/map_rom.c @@ -20,8 +20,10 @@ static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_ch static void maprom_nop (struct mtd_info *); static struct mtd_info *map_rom_probe(struct map_info *map); static int maprom_erase (struct mtd_info *mtd, struct erase_info *info); -static unsigned long maprom_unmapped_area(struct mtd_info *, unsigned long, - unsigned long, unsigned long); +static int maprom_point (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, void **virt, resource_size_t *phys); +static int maprom_unpoint(struct mtd_info *mtd, loff_t from, size_t len); + static struct mtd_chip_driver maprom_chipdrv = { .probe = map_rom_probe, @@ -51,7 +53,8 @@ static struct mtd_info *map_rom_probe(struct map_info *map) mtd->name = map->name; mtd->type = MTD_ROM; mtd->size = map->size; - mtd->_get_unmapped_area = maprom_unmapped_area; + mtd->_point = maprom_point; + mtd->_unpoint = maprom_unpoint; mtd->_read = maprom_read; mtd->_write = maprom_write; mtd->_sync = maprom_nop; @@ -66,18 +69,23 @@ static struct mtd_info *map_rom_probe(struct map_info *map) } -/* - * Allow NOMMU mmap() to directly map the device (if not NULL) - * - return the address to which the offset maps - * - return -ENOSYS to indicate refusal to do the mapping - */ -static unsigned long maprom_unmapped_area(struct mtd_info *mtd, - unsigned long len, - unsigned long offset, - unsigned long flags) +static int maprom_point(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, void **virt, resource_size_t *phys) { struct map_info *map = mtd->priv; - return (unsigned long) map->virt + offset; + + if (!map->virt) + return -EINVAL; + *virt = map->virt + from; + if (phys) + *phys = map->phys + from; + *retlen = len; + return 0; +} + +static int maprom_unpoint(struct mtd_info *mtd, loff_t from, size_t len) +{ + return 0; } static int maprom_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 84b16133554b..0806f72102c0 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1814,8 +1814,13 @@ static void __init doc_dbg_register(struct mtd_info *floor) struct dentry *root = floor->dbg.dfs_dir; struct docg3 *docg3 = floor->priv; - if (IS_ERR_OR_NULL(root)) + if (IS_ERR_OR_NULL(root)) { + if (IS_ENABLED(CONFIG_DEBUG_FS) && + !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + dev_warn(floor->dev.parent, + "CONFIG_MTD_PARTITIONED_MASTER must be enabled to expose debugfs stuff\n"); return; + } debugfs_create_file("docg3_flashcontrol", S_IRUSR, root, docg3, &flashcontrol_fops); diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 268aae45b514..555b94406e0b 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -583,7 +583,7 @@ static struct mtd_erase_region_info erase_regions[] = { } }; -static struct mtd_partition lart_partitions[] = { +static const struct mtd_partition lart_partitions[] = { /* blob */ { .name = "blob", diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 00eea6fd379c..dbe6a1de2bb8 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -359,6 +359,7 @@ static const struct spi_device_id m25p_ids[] = { {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, /* Everspin MRAMs (non-JEDEC) */ + { "mr25h128" }, /* 128 Kib, 40 MHz */ { "mr25h256" }, /* 256 Kib, 40 MHz */ { "mr25h10" }, /* 1 Mib, 40 MHz */ { "mr25h40" }, /* 4 Mib, 40 MHz */ diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index cbd8547d7aad..0bf4aeaf0cb8 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/ioport.h> #include <linux/vmalloc.h> +#include <linux/mm.h> #include <linux/init.h> #include <linux/mtd/mtd.h> #include <linux/mtd/mtdram.h> @@ -69,6 +70,27 @@ static int ram_point(struct mtd_info *mtd, loff_t from, size_t len, { *virt = mtd->priv + from; *retlen = len; + + if (phys) { + /* limit retlen to the number of contiguous physical pages */ + unsigned long page_ofs = offset_in_page(*virt); + void *addr = *virt - page_ofs; + unsigned long pfn1, pfn0 = vmalloc_to_pfn(addr); + + *phys = __pfn_to_phys(pfn0) + page_ofs; + len += page_ofs; + while (len > PAGE_SIZE) { + len -= PAGE_SIZE; + addr += PAGE_SIZE; + pfn0++; + pfn1 = vmalloc_to_pfn(addr); + if (pfn1 != pfn0) { + *retlen = addr - *virt; + break; + } + } + } + return 0; } @@ -77,19 +99,6 @@ static int ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) return 0; } -/* - * Allow NOMMU mmap() to directly map the device (if not NULL) - * - return the address to which the offset maps - * - return -ENOSYS to indicate refusal to do the mapping - */ -static unsigned long ram_get_unmapped_area(struct mtd_info *mtd, - unsigned long len, - unsigned long offset, - unsigned long flags) -{ - return (unsigned long) mtd->priv + offset; -} - static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -134,7 +143,6 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, mtd->_erase = ram_erase; mtd->_point = ram_point; mtd->_unpoint = ram_unpoint; - mtd->_get_unmapped_area = ram_get_unmapped_area; mtd->_read = ram_read; mtd->_write = ram_write; diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 8087c36dc693..0ec85f316d24 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -163,8 +163,9 @@ static int register_device(char *name, unsigned long start, unsigned long length } if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start = - ioremap(start, length))) { - E("slram: ioremap failed\n"); + memremap(start, length, + MEMREMAP_WB | MEMREMAP_WT | MEMREMAP_WC))) { + E("slram: memremap failed\n"); return -EIO; } ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end = @@ -186,7 +187,7 @@ static int register_device(char *name, unsigned long start, unsigned long length if (mtd_device_register((*curmtd)->mtdinfo, NULL, 0)) { E("slram: Failed to register new device\n"); - iounmap(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start); + memunmap(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start); kfree((*curmtd)->mtdinfo->priv); kfree((*curmtd)->mtdinfo); return(-EAGAIN); @@ -206,7 +207,7 @@ static void unregister_devices(void) while (slram_mtdlist) { nextitem = slram_mtdlist->next; mtd_device_unregister(slram_mtdlist->mtdinfo); - iounmap(((slram_priv_t *)slram_mtdlist->mtdinfo->priv)->start); + memunmap(((slram_priv_t *)slram_mtdlist->mtdinfo->priv)->start); kfree(slram_mtdlist->mtdinfo->priv); kfree(slram_mtdlist->mtdinfo); kfree(slram_mtdlist); diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index d504b3d1791d..70f488628464 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -61,7 +61,7 @@ static struct map_info flagadm_map = { .bankwidth = 2, }; -static struct mtd_partition flagadm_parts[] = { +static const struct mtd_partition flagadm_parts[] = { { .name = "Bootloader", .offset = FLASH_PARTITION0_ADDR, diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 15bbda03be65..a0b8fa7849a9 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -47,7 +47,7 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = { /* * MTD partitioning stuff */ -static struct mtd_partition partitions[] = +static const struct mtd_partition partitions[] = { { .name = "FileSystem", diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c index 81dc2598bc0a..3528497f96c7 100644 --- a/drivers/mtd/maps/netsc520.c +++ b/drivers/mtd/maps/netsc520.c @@ -52,7 +52,7 @@ /* partition_info gives details on the logical partitions that the split the * single flash device into. If the size if zero we use up to the end of the * device. */ -static struct mtd_partition partition_info[]={ +static const struct mtd_partition partition_info[] = { { .name = "NetSc520 boot kernel", .offset = 0, diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index a577ef8553d0..729579fb654f 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -107,7 +107,7 @@ static struct map_info nettel_amd_map = { .bankwidth = AMD_BUSWIDTH, }; -static struct mtd_partition nettel_amd_partitions[] = { +static const struct mtd_partition nettel_amd_partitions[] = { { .name = "SnapGear BIOS config", .offset = 0x000e0000, diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 51572895c02c..6d9a4d6f9839 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -43,7 +43,6 @@ struct platram_info { struct device *dev; struct mtd_info *mtd; struct map_info map; - struct resource *area; struct platdata_mtd_ram *pdata; }; @@ -97,16 +96,6 @@ static int platram_remove(struct platform_device *pdev) platram_setrw(info, PLATRAM_RO); - /* release resources */ - - if (info->area) { - release_resource(info->area); - kfree(info->area); - } - - if (info->map.virt != NULL) - iounmap(info->map.virt); - kfree(info); return 0; @@ -147,12 +136,11 @@ static int platram_probe(struct platform_device *pdev) info->pdata = pdata; /* get the resource for the memory mapping */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - if (res == NULL) { - dev_err(&pdev->dev, "no memory resource specified\n"); - err = -ENOENT; + info->map.virt = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->map.virt)) { + err = PTR_ERR(info->map.virt); + dev_err(&pdev->dev, "failed to ioremap() region\n"); goto exit_free; } @@ -167,26 +155,8 @@ static int platram_probe(struct platform_device *pdev) (char *)pdata->mapname : (char *)pdev->name; info->map.bankwidth = pdata->bankwidth; - /* register our usage of the memory area */ - - info->area = request_mem_region(res->start, info->map.size, pdev->name); - if (info->area == NULL) { - dev_err(&pdev->dev, "failed to request memory region\n"); - err = -EIO; - goto exit_free; - } - - /* remap the memory area */ - - info->map.virt = ioremap(res->start, info->map.size); dev_dbg(&pdev->dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size); - if (info->map.virt == NULL) { - dev_err(&pdev->dev, "failed to ioremap() region\n"); - err = -EIO; - goto exit_free; - } - simple_map_init(&info->map); dev_dbg(&pdev->dev, "initialised map, probing for mtd\n"); diff --git a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c index 556a2dfe94c5..4337d279ad83 100644 --- a/drivers/mtd/maps/sbc_gxx.c +++ b/drivers/mtd/maps/sbc_gxx.c @@ -87,7 +87,7 @@ static DEFINE_SPINLOCK(sbc_gxx_spin); /* partition_info gives details on the logical partitions that the split the * single flash device into. If the size if zero we use up to the end of the * device. */ -static struct mtd_partition partition_info[]={ +static const struct mtd_partition partition_info[] = { { .name = "SBC-GXx flash boot partition", .offset = 0, .size = BOOT_PARTITION_SIZE_KiB*1024 }, diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index 9969fedb1f13..8f177e0acb8c 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c @@ -43,7 +43,7 @@ static struct map_info ts5500_map = { .phys = WINDOW_ADDR }; -static struct mtd_partition ts5500_partitions[] = { +static const struct mtd_partition ts5500_partitions[] = { { .name = "Drive A", .offset = 0, diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 00a8190797ec..aef030ca8601 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -49,7 +49,7 @@ static struct mtd_info *uclinux_ram_mtdinfo; /****************************************************************************/ -static struct mtd_partition uclinux_romfs[] = { +static const struct mtd_partition uclinux_romfs[] = { { .name = "ROMfs" } }; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index d573606b91c2..60bf53df5454 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -644,32 +644,6 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs) } /* - * try to support NOMMU mmaps on concatenated devices - * - we don't support subdev spanning as we can't guarantee it'll work - */ -static unsigned long concat_get_unmapped_area(struct mtd_info *mtd, - unsigned long len, - unsigned long offset, - unsigned long flags) -{ - struct mtd_concat *concat = CONCAT(mtd); - int i; - - for (i = 0; i < concat->num_subdev; i++) { - struct mtd_info *subdev = concat->subdev[i]; - - if (offset >= subdev->size) { - offset -= subdev->size; - continue; - } - - return mtd_get_unmapped_area(subdev, len, offset, flags); - } - - return (unsigned long) -ENOSYS; -} - -/* * This function constructs a virtual MTD device by concatenating * num_devs MTD devices. A pointer to the new device object is * stored to *new_dev upon success. This function does _not_ @@ -790,7 +764,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd._unlock = concat_unlock; concat->mtd._suspend = concat_suspend; concat->mtd._resume = concat_resume; - concat->mtd._get_unmapped_area = concat_get_unmapped_area; /* * Combine the erase block size info of the subdevices: diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index e7ea842ba3db..f80e911b8843 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1022,11 +1022,18 @@ EXPORT_SYMBOL_GPL(mtd_unpoint); unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len, unsigned long offset, unsigned long flags) { - if (!mtd->_get_unmapped_area) - return -EOPNOTSUPP; - if (offset >= mtd->size || len > mtd->size - offset) - return -EINVAL; - return mtd->_get_unmapped_area(mtd, len, offset, flags); + size_t retlen; + void *virt; + int ret; + + ret = mtd_point(mtd, offset, len, &retlen, &virt, NULL); + if (ret) + return ret; + if (retlen != len) { + mtd_unpoint(mtd, offset, retlen); + return -ENOSYS; + } + return (unsigned long)virt; } EXPORT_SYMBOL_GPL(mtd_get_unmapped_area); @@ -1093,6 +1100,39 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, } EXPORT_SYMBOL_GPL(mtd_panic_write); +static int mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs, + struct mtd_oob_ops *ops) +{ + /* + * Some users are setting ->datbuf or ->oobbuf to NULL, but are leaving + * ->len or ->ooblen uninitialized. Force ->len and ->ooblen to 0 in + * this case. + */ + if (!ops->datbuf) + ops->len = 0; + + if (!ops->oobbuf) + ops->ooblen = 0; + + if (offs < 0 || offs + ops->len >= mtd->size) + return -EINVAL; + + if (ops->ooblen) { + u64 maxooblen; + + if (ops->ooboffs >= mtd_oobavail(mtd, ops)) + return -EINVAL; + + maxooblen = ((mtd_div_by_ws(mtd->size, mtd) - + mtd_div_by_ws(offs, mtd)) * + mtd_oobavail(mtd, ops)) - ops->ooboffs; + if (ops->ooblen > maxooblen) + return -EINVAL; + } + + return 0; +} + int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { int ret_code; @@ -1100,6 +1140,10 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) if (!mtd->_read_oob) return -EOPNOTSUPP; + ret_code = mtd_check_oob_ops(mtd, from, ops); + if (ret_code) + return ret_code; + ledtrig_mtd_activity(); /* * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics @@ -1119,11 +1163,18 @@ EXPORT_SYMBOL_GPL(mtd_read_oob); int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { + int ret; + ops->retlen = ops->oobretlen = 0; if (!mtd->_write_oob) return -EOPNOTSUPP; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; + + ret = mtd_check_oob_ops(mtd, to, ops); + if (ret) + return ret; + ledtrig_mtd_activity(); return mtd->_write_oob(mtd, to, ops); } |