diff options
Diffstat (limited to 'drivers')
29 files changed, 700 insertions, 177 deletions
diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c index ff86373d7d24..a05e103682a4 100644 --- a/drivers/mtd/chips/chipreg.c +++ b/drivers/mtd/chips/chipreg.c @@ -31,14 +31,11 @@ void unregister_mtd_chip_driver(struct mtd_chip_driver *drv) static struct mtd_chip_driver *get_mtd_chip_driver (const char *name) { - struct list_head *pos; struct mtd_chip_driver *ret = NULL, *this; spin_lock(&chip_drvs_lock); - list_for_each(pos, &chip_drvs_list) { - this = list_entry(pos, typeof(*this), list); - + list_for_each_entry(this, &chip_drvs_list, list) { if (!strcmp(this->name, name)) { ret = this; break; diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 0f4c2d823de8..79cb981ececc 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -89,6 +89,12 @@ config MTD_MCHP23K256 platform data, or a device tree description if you want to specify device partitioning +config MTD_MCHP48L640 + tristate "Microchip 48L640 EERAM" + depends on SPI_MASTER + help + This enables access to Microchip 48L640 EERAM chips, using SPI. + config MTD_SPEAR_SMI tristate "SPEAR MTD NOR Support through SMI controller" depends on PLAT_SPEAR || COMPILE_TEST diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 991c8d12c016..0362cf6bdc67 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_MCHP23K256) += mchp23k256.o +obj-$(CONFIG_MTD_MCHP48L640) += mchp48l640.o obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o diff --git a/drivers/mtd/devices/mchp48l640.c b/drivers/mtd/devices/mchp48l640.c new file mode 100644 index 000000000000..efc2003bd13a --- /dev/null +++ b/drivers/mtd/devices/mchp48l640.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Microchip 48L640 64 Kb SPI Serial EERAM + * + * Copyright Heiko Schocher <hs@denx.de> + * + * datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/20006055B.pdf + * + * we set continuous mode but reading/writing more bytes than + * pagesize seems to bring chip into state where readden values + * are wrong ... no idea why. + * + */ +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/jiffies.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mutex.h> +#include <linux/sched.h> +#include <linux/sizes.h> +#include <linux/spi/flash.h> +#include <linux/spi/spi.h> +#include <linux/of_device.h> + +struct mchp48_caps { + unsigned int size; + unsigned int page_size; +}; + +struct mchp48l640_flash { + struct spi_device *spi; + struct mutex lock; + struct mtd_info mtd; + const struct mchp48_caps *caps; +}; + +#define MCHP48L640_CMD_WREN 0x06 +#define MCHP48L640_CMD_WRDI 0x04 +#define MCHP48L640_CMD_WRITE 0x02 +#define MCHP48L640_CMD_READ 0x03 +#define MCHP48L640_CMD_WRSR 0x01 +#define MCHP48L640_CMD_RDSR 0x05 + +#define MCHP48L640_STATUS_RDY 0x01 +#define MCHP48L640_STATUS_WEL 0x02 +#define MCHP48L640_STATUS_BP0 0x04 +#define MCHP48L640_STATUS_BP1 0x08 +#define MCHP48L640_STATUS_SWM 0x10 +#define MCHP48L640_STATUS_PRO 0x20 +#define MCHP48L640_STATUS_ASE 0x40 + +#define MCHP48L640_TIMEOUT 100 + +#define MAX_CMD_SIZE 0x10 + +#define to_mchp48l640_flash(x) container_of(x, struct mchp48l640_flash, mtd) + +static int mchp48l640_mkcmd(struct mchp48l640_flash *flash, u8 cmd, loff_t addr, char *buf) +{ + buf[0] = cmd; + buf[1] = addr >> 8; + buf[2] = addr; + + return 3; +} + +static int mchp48l640_read_status(struct mchp48l640_flash *flash, int *status) +{ + unsigned char cmd[2]; + int ret; + + cmd[0] = MCHP48L640_CMD_RDSR; + cmd[1] = 0x00; + mutex_lock(&flash->lock); + ret = spi_write_then_read(flash->spi, &cmd[0], 1, &cmd[1], 1); + mutex_unlock(&flash->lock); + if (!ret) + *status = cmd[1]; + dev_dbg(&flash->spi->dev, "read status ret: %d status: %x", ret, *status); + + return ret; +} + +static int mchp48l640_waitforbit(struct mchp48l640_flash *flash, int bit, bool set) +{ + int ret, status; + unsigned long deadline; + + deadline = jiffies + msecs_to_jiffies(MCHP48L640_TIMEOUT); + do { + ret = mchp48l640_read_status(flash, &status); + dev_dbg(&flash->spi->dev, "read status ret: %d bit: %x %sset status: %x", + ret, bit, (set ? "" : "not"), status); + if (ret) + return ret; + + if (set) { + if ((status & bit) == bit) + return 0; + } else { + if ((status & bit) == 0) + return 0; + } + + usleep_range(1000, 2000); + } while (!time_after_eq(jiffies, deadline)); + + dev_err(&flash->spi->dev, "Timeout waiting for bit %x %s set in status register.", + bit, (set ? "" : "not")); + return -ETIMEDOUT; +} + +static int mchp48l640_write_prepare(struct mchp48l640_flash *flash, bool enable) +{ + unsigned char cmd[2]; + int ret; + + if (enable) + cmd[0] = MCHP48L640_CMD_WREN; + else + cmd[0] = MCHP48L640_CMD_WRDI; + + mutex_lock(&flash->lock); + ret = spi_write(flash->spi, cmd, 1); + mutex_unlock(&flash->lock); + + if (ret) + dev_err(&flash->spi->dev, "write %sable failed ret: %d", + (enable ? "en" : "dis"), ret); + + dev_dbg(&flash->spi->dev, "write %sable success ret: %d", + (enable ? "en" : "dis"), ret); + if (enable) + return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_WEL, true); + + return ret; +} + +static int mchp48l640_set_mode(struct mchp48l640_flash *flash) +{ + unsigned char cmd[2]; + int ret; + + ret = mchp48l640_write_prepare(flash, true); + if (ret) + return ret; + + cmd[0] = MCHP48L640_CMD_WRSR; + cmd[1] = MCHP48L640_STATUS_PRO; + + mutex_lock(&flash->lock); + ret = spi_write(flash->spi, cmd, 2); + mutex_unlock(&flash->lock); + if (ret) + dev_err(&flash->spi->dev, "Could not set continuous mode ret: %d", ret); + + return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_PRO, true); +} + +static int mchp48l640_wait_rdy(struct mchp48l640_flash *flash) +{ + return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_RDY, false); +}; + +static int mchp48l640_write_page(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const unsigned char *buf) +{ + struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd); + unsigned char *cmd; + int ret; + int cmdlen; + + cmd = kmalloc((3 + len), GFP_KERNEL | GFP_DMA); + if (!cmd) + return -ENOMEM; + + ret = mchp48l640_wait_rdy(flash); + if (ret) + goto fail; + + ret = mchp48l640_write_prepare(flash, true); + if (ret) + goto fail; + + mutex_lock(&flash->lock); + cmdlen = mchp48l640_mkcmd(flash, MCHP48L640_CMD_WRITE, to, cmd); + memcpy(&cmd[cmdlen], buf, len); + ret = spi_write(flash->spi, cmd, cmdlen + len); + mutex_unlock(&flash->lock); + if (!ret) + *retlen += len; + else + goto fail; + + ret = mchp48l640_waitforbit(flash, MCHP48L640_STATUS_WEL, false); + if (ret) + goto fail; + + kfree(cmd); + return 0; +fail: + kfree(cmd); + dev_err(&flash->spi->dev, "write fail with: %d", ret); + return ret; +}; + +static int mchp48l640_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const unsigned char *buf) +{ + struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd); + int ret; + size_t wlen = 0; + loff_t woff = to; + size_t ws; + size_t page_sz = flash->caps->page_size; + + /* + * we set PRO bit (page rollover), but writing length > page size + * does result in total chaos, so write in 32 byte chunks. + */ + while (wlen < len) { + ws = min((len - wlen), page_sz); + ret = mchp48l640_write_page(mtd, woff, ws, retlen, &buf[wlen]); + if (ret) + return ret; + wlen += ws; + woff += ws; + } + + return ret; +} + +static int mchp48l640_read_page(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, unsigned char *buf) +{ + struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd); + unsigned char *cmd; + int ret; + int cmdlen; + + cmd = kmalloc((3 + len), GFP_KERNEL | GFP_DMA); + if (!cmd) + return -ENOMEM; + + ret = mchp48l640_wait_rdy(flash); + if (ret) + goto fail; + + mutex_lock(&flash->lock); + cmdlen = mchp48l640_mkcmd(flash, MCHP48L640_CMD_READ, from, cmd); + ret = spi_write_then_read(flash->spi, cmd, cmdlen, buf, len); + mutex_unlock(&flash->lock); + if (!ret) + *retlen += len; + + return ret; + +fail: + kfree(cmd); + dev_err(&flash->spi->dev, "read fail with: %d", ret); + return ret; +} + +static int mchp48l640_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, unsigned char *buf) +{ + struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd); + int ret; + size_t wlen = 0; + loff_t woff = from; + size_t ws; + size_t page_sz = flash->caps->page_size; + + /* + * we set PRO bit (page rollover), but if read length > page size + * does result in total chaos in result ... + */ + while (wlen < len) { + ws = min((len - wlen), page_sz); + ret = mchp48l640_read_page(mtd, woff, ws, retlen, &buf[wlen]); + if (ret) + return ret; + wlen += ws; + woff += ws; + } + + return ret; +}; + +static const struct mchp48_caps mchp48l640_caps = { + .size = SZ_8K, + .page_size = 32, +}; + +static int mchp48l640_probe(struct spi_device *spi) +{ + struct mchp48l640_flash *flash; + struct flash_platform_data *data; + int err; + int status; + + flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); + if (!flash) + return -ENOMEM; + + flash->spi = spi; + mutex_init(&flash->lock); + spi_set_drvdata(spi, flash); + + err = mchp48l640_read_status(flash, &status); + if (err) + return err; + + err = mchp48l640_set_mode(flash); + if (err) + return err; + + data = dev_get_platdata(&spi->dev); + + flash->caps = of_device_get_match_data(&spi->dev); + if (!flash->caps) + flash->caps = &mchp48l640_caps; + + mtd_set_of_node(&flash->mtd, spi->dev.of_node); + flash->mtd.dev.parent = &spi->dev; + flash->mtd.type = MTD_RAM; + flash->mtd.flags = MTD_CAP_RAM; + flash->mtd.writesize = flash->caps->page_size; + flash->mtd.size = flash->caps->size; + flash->mtd._read = mchp48l640_read; + flash->mtd._write = mchp48l640_write; + + err = mtd_device_register(&flash->mtd, data ? data->parts : NULL, + data ? data->nr_parts : 0); + if (err) + return err; + + return 0; +} + +static int mchp48l640_remove(struct spi_device *spi) +{ + struct mchp48l640_flash *flash = spi_get_drvdata(spi); + + return mtd_device_unregister(&flash->mtd); +} + +static const struct of_device_id mchp48l640_of_table[] = { + { + .compatible = "microchip,48l640", + .data = &mchp48l640_caps, + }, + {} +}; +MODULE_DEVICE_TABLE(of, mchp48l640_of_table); + +static struct spi_driver mchp48l640_driver = { + .driver = { + .name = "mchp48l640", + .of_match_table = of_match_ptr(mchp48l640_of_table), + }, + .probe = mchp48l640_probe, + .remove = mchp48l640_remove, +}; + +module_spi_driver(mchp48l640_driver); + +MODULE_DESCRIPTION("MTD SPI driver for Microchip 48l640 EERAM chips"); +MODULE_AUTHOR("Heiko Schocher <hs@denx.de>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:mchp48l640"); diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index fb4a6aa24543..08f76ff839a7 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c @@ -286,7 +286,6 @@ static int __init ms02nv_init(void) break; default: return -ENODEV; - break; } for (i = 0; i < ARRAY_SIZE(ms02nv_addrs); i++) diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 5b04ae6c3057..6ed6c51fac69 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -270,6 +270,7 @@ static int phram_setup(const char *val) if (len == 0 || erasesize == 0 || erasesize > len || erasesize > UINT_MAX || rem) { parse_err("illegal erasesize or len\n"); + ret = -EINVAL; goto error; } diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index af16d3485de0..6276daa296da 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -259,20 +259,13 @@ static int find_boot_record(struct INFTLrecord *inftl) /* Memory alloc */ inftl->PUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16), GFP_KERNEL); - if (!inftl->PUtable) { - printk(KERN_WARNING "INFTL: allocation of PUtable " - "failed (%zd bytes)\n", - inftl->nb_blocks * sizeof(u16)); + if (!inftl->PUtable) return -ENOMEM; - } inftl->VUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16), GFP_KERNEL); if (!inftl->VUtable) { kfree(inftl->PUtable); - printk(KERN_WARNING "INFTL: allocation of VUtable " - "failed (%zd bytes)\n", - inftl->nb_blocks * sizeof(u16)); return -ENOMEM; } @@ -330,7 +323,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL); if (!buf) - return -1; + return -ENOMEM; ret = -1; for (i = 0; i < len; i += SECTORSIZE) { @@ -558,12 +551,8 @@ int INFTL_mount(struct INFTLrecord *s) /* Temporary buffer to store ANAC numbers. */ ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL); - if (!ANACtable) { - printk(KERN_WARNING "INFTL: allocation of ANACtable " - "failed (%zd bytes)\n", - s->nb_blocks * sizeof(u8)); + if (!ANACtable) return -ENOMEM; - } /* * First pass is to explore each physical unit, and construct the diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 42a95ba40f2c..281fcbaa74e7 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -189,10 +189,8 @@ static int amd76xrom_init_one(struct pci_dev *pdev, if (!map) { map = kmalloc(sizeof(*map), GFP_KERNEL); - } - if (!map) { - printk(KERN_ERR MOD_NAME ": kmalloc failed"); - goto out; + if (!map) + goto out; } memset(map, 0, sizeof(*map)); INIT_LIST_HEAD(&map->list); diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 460494212f6a..c0216bc740cc 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -217,12 +217,10 @@ static int __init ck804xrom_init_one(struct pci_dev *pdev, unsigned long offset; int i; - if (!map) - map = kmalloc(sizeof(*map), GFP_KERNEL); - if (!map) { - printk(KERN_ERR MOD_NAME ": kmalloc failed"); - goto out; + map = kmalloc(sizeof(*map), GFP_KERNEL); + if (!map) + goto out; } memset(map, 0, sizeof(*map)); INIT_LIST_HEAD(&map->list); diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index 85e14150a073..15d5b76ff504 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -277,11 +277,10 @@ static int __init esb2rom_init_one(struct pci_dev *pdev, unsigned long offset; int i; - if (!map) - map = kmalloc(sizeof(*map), GFP_KERNEL); if (!map) { - printk(KERN_ERR MOD_NAME ": kmalloc failed"); - goto out; + map = kmalloc(sizeof(*map), GFP_KERNEL); + if (!map) + goto out; } memset(map, 0, sizeof(*map)); INIT_LIST_HEAD(&map->list); diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index fda72c5fd8f9..c8b2793691db 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -213,10 +213,8 @@ static int __init ichxrom_init_one(struct pci_dev *pdev, if (!map) { map = kmalloc(sizeof(*map), GFP_KERNEL); - } - if (!map) { - printk(KERN_ERR MOD_NAME ": kmalloc failed"); - goto out; + if (!map) + goto out; } memset(map, 0, sizeof(*map)); INIT_LIST_HEAD(&map->list); diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 0bec7c791d17..cedd8ef9a6bf 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -127,7 +127,6 @@ static int platram_probe(struct platform_device *pdev) 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; } diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index f9cfb084c029..6c0c91bfec05 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -62,10 +62,8 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp) } up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL); - if (!up) { - printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n"); + if (!up) return -ENOMEM; - } /* copy defaults and tweak parameters */ memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ)); diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 9aaeadd53eb4..b5ccd3037788 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -96,6 +96,12 @@ static void mtd_release(struct device *dev) device_destroy(&mtd_class, index + 1); } +#define MTD_DEVICE_ATTR_RO(name) \ +static DEVICE_ATTR(name, 0444, mtd_##name##_show, NULL) + +#define MTD_DEVICE_ATTR_RW(name) \ +static DEVICE_ATTR(name, 0644, mtd_##name##_show, mtd_##name##_store) + static ssize_t mtd_type_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -131,46 +137,45 @@ static ssize_t mtd_type_show(struct device *dev, type = "unknown"; } - return snprintf(buf, PAGE_SIZE, "%s\n", type); + return sysfs_emit(buf, "%s\n", type); } -static DEVICE_ATTR(type, S_IRUGO, mtd_type_show, NULL); +MTD_DEVICE_ATTR_RO(type); static ssize_t mtd_flags_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)mtd->flags); + return sysfs_emit(buf, "0x%lx\n", (unsigned long)mtd->flags); } -static DEVICE_ATTR(flags, S_IRUGO, mtd_flags_show, NULL); +MTD_DEVICE_ATTR_RO(flags); static ssize_t mtd_size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%llu\n", - (unsigned long long)mtd->size); + return sysfs_emit(buf, "%llu\n", (unsigned long long)mtd->size); } -static DEVICE_ATTR(size, S_IRUGO, mtd_size_show, NULL); +MTD_DEVICE_ATTR_RO(size); static ssize_t mtd_erasesize_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->erasesize); + return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize); } -static DEVICE_ATTR(erasesize, S_IRUGO, mtd_erasesize_show, NULL); +MTD_DEVICE_ATTR_RO(erasesize); static ssize_t mtd_writesize_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->writesize); + return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->writesize); } -static DEVICE_ATTR(writesize, S_IRUGO, mtd_writesize_show, NULL); +MTD_DEVICE_ATTR_RO(writesize); static ssize_t mtd_subpagesize_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -178,55 +183,54 @@ static ssize_t mtd_subpagesize_show(struct device *dev, struct mtd_info *mtd = dev_get_drvdata(dev); unsigned int subpagesize = mtd->writesize >> mtd->subpage_sft; - return snprintf(buf, PAGE_SIZE, "%u\n", subpagesize); + return sysfs_emit(buf, "%u\n", subpagesize); } -static DEVICE_ATTR(subpagesize, S_IRUGO, mtd_subpagesize_show, NULL); +MTD_DEVICE_ATTR_RO(subpagesize); static ssize_t mtd_oobsize_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->oobsize); + return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->oobsize); } -static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL); +MTD_DEVICE_ATTR_RO(oobsize); static ssize_t mtd_oobavail_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", mtd->oobavail); + return sysfs_emit(buf, "%u\n", mtd->oobavail); } -static DEVICE_ATTR(oobavail, S_IRUGO, mtd_oobavail_show, NULL); +MTD_DEVICE_ATTR_RO(oobavail); static ssize_t mtd_numeraseregions_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", mtd->numeraseregions); + return sysfs_emit(buf, "%u\n", mtd->numeraseregions); } -static DEVICE_ATTR(numeraseregions, S_IRUGO, mtd_numeraseregions_show, - NULL); +MTD_DEVICE_ATTR_RO(numeraseregions); static ssize_t mtd_name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", mtd->name); + return sysfs_emit(buf, "%s\n", mtd->name); } -static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL); +MTD_DEVICE_ATTR_RO(name); static ssize_t mtd_ecc_strength_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_strength); + return sysfs_emit(buf, "%u\n", mtd->ecc_strength); } -static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL); +MTD_DEVICE_ATTR_RO(ecc_strength); static ssize_t mtd_bitflip_threshold_show(struct device *dev, struct device_attribute *attr, @@ -234,7 +238,7 @@ static ssize_t mtd_bitflip_threshold_show(struct device *dev, { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", mtd->bitflip_threshold); + return sysfs_emit(buf, "%u\n", mtd->bitflip_threshold); } static ssize_t mtd_bitflip_threshold_store(struct device *dev, @@ -252,60 +256,57 @@ static ssize_t mtd_bitflip_threshold_store(struct device *dev, mtd->bitflip_threshold = bitflip_threshold; return count; } -static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR, - mtd_bitflip_threshold_show, - mtd_bitflip_threshold_store); +MTD_DEVICE_ATTR_RW(bitflip_threshold); static ssize_t mtd_ecc_step_size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_step_size); + return sysfs_emit(buf, "%u\n", mtd->ecc_step_size); } -static DEVICE_ATTR(ecc_step_size, S_IRUGO, mtd_ecc_step_size_show, NULL); +MTD_DEVICE_ATTR_RO(ecc_step_size); -static ssize_t mtd_ecc_stats_corrected_show(struct device *dev, +static ssize_t mtd_corrected_bits_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats; - return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->corrected); + return sysfs_emit(buf, "%u\n", ecc_stats->corrected); } -static DEVICE_ATTR(corrected_bits, S_IRUGO, - mtd_ecc_stats_corrected_show, NULL); +MTD_DEVICE_ATTR_RO(corrected_bits); /* ecc stats corrected */ -static ssize_t mtd_ecc_stats_errors_show(struct device *dev, +static ssize_t mtd_ecc_failures_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats; - return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->failed); + return sysfs_emit(buf, "%u\n", ecc_stats->failed); } -static DEVICE_ATTR(ecc_failures, S_IRUGO, mtd_ecc_stats_errors_show, NULL); +MTD_DEVICE_ATTR_RO(ecc_failures); /* ecc stats errors */ -static ssize_t mtd_badblocks_show(struct device *dev, +static ssize_t mtd_bad_blocks_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats; - return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->badblocks); + return sysfs_emit(buf, "%u\n", ecc_stats->badblocks); } -static DEVICE_ATTR(bad_blocks, S_IRUGO, mtd_badblocks_show, NULL); +MTD_DEVICE_ATTR_RO(bad_blocks); -static ssize_t mtd_bbtblocks_show(struct device *dev, +static ssize_t mtd_bbt_blocks_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats; - return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->bbtblocks); + return sysfs_emit(buf, "%u\n", ecc_stats->bbtblocks); } -static DEVICE_ATTR(bbt_blocks, S_IRUGO, mtd_bbtblocks_show, NULL); +MTD_DEVICE_ATTR_RO(bbt_blocks); static struct attribute *mtd_attrs[] = { &dev_attr_type.attr, @@ -361,6 +362,7 @@ static struct dentry *dfs_dir_mtd; static void mtd_debugfs_populate(struct mtd_info *mtd) { + struct mtd_info *master = mtd_get_master(mtd); struct device *dev = &mtd->dev; struct dentry *root; @@ -370,12 +372,12 @@ static void mtd_debugfs_populate(struct mtd_info *mtd) root = debugfs_create_dir(dev_name(dev), dfs_dir_mtd); mtd->dbg.dfs_dir = root; - if (mtd->dbg.partid) - debugfs_create_file("partid", 0400, root, mtd, + if (master->dbg.partid) + debugfs_create_file("partid", 0400, root, master, &mtd_partid_debug_fops); - if (mtd->dbg.partname) - debugfs_create_file("partname", 0400, root, mtd, + if (master->dbg.partname) + debugfs_create_file("partname", 0400, root, master, &mtd_partname_debug_fops); } @@ -777,6 +779,148 @@ static void mtd_set_dev_defaults(struct mtd_info *mtd) mutex_init(&mtd->master.chrdev_lock); } +static ssize_t mtd_otp_size(struct mtd_info *mtd, bool is_user) +{ + struct otp_info *info; + ssize_t size = 0; + unsigned int i; + size_t retlen; + int ret; + + info = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!info) + return -ENOMEM; + + if (is_user) + ret = mtd_get_user_prot_info(mtd, PAGE_SIZE, &retlen, info); + else + ret = mtd_get_fact_prot_info(mtd, PAGE_SIZE, &retlen, info); + if (ret) + goto err; + + for (i = 0; i < retlen / sizeof(*info); i++) + size += info[i].length; + + kfree(info); + return size; + +err: + kfree(info); + return ret; +} + +static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, + const char *compatible, + int size, + nvmem_reg_read_t reg_read) +{ + struct nvmem_device *nvmem = NULL; + struct nvmem_config config = {}; + struct device_node *np; + + /* DT binding is optional */ + np = of_get_compatible_child(mtd->dev.of_node, compatible); + + /* OTP nvmem will be registered on the physical device */ + config.dev = mtd->dev.parent; + /* just reuse the compatible as name */ + config.name = compatible; + config.id = NVMEM_DEVID_NONE; + config.owner = THIS_MODULE; + config.type = NVMEM_TYPE_OTP; + config.root_only = true; + config.reg_read = reg_read; + config.size = size; + config.of_node = np; + config.priv = mtd; + + nvmem = nvmem_register(&config); + /* Just ignore if there is no NVMEM support in the kernel */ + if (IS_ERR(nvmem) && PTR_ERR(nvmem) == -EOPNOTSUPP) + nvmem = NULL; + + of_node_put(np); + + return nvmem; +} + +static int mtd_nvmem_user_otp_reg_read(void *priv, unsigned int offset, + void *val, size_t bytes) +{ + struct mtd_info *mtd = priv; + size_t retlen; + int ret; + + ret = mtd_read_user_prot_reg(mtd, offset, bytes, &retlen, val); + if (ret) + return ret; + + return retlen == bytes ? 0 : -EIO; +} + +static int mtd_nvmem_fact_otp_reg_read(void *priv, unsigned int offset, + void *val, size_t bytes) +{ + struct mtd_info *mtd = priv; + size_t retlen; + int ret; + + ret = mtd_read_fact_prot_reg(mtd, offset, bytes, &retlen, val); + if (ret) + return ret; + + return retlen == bytes ? 0 : -EIO; +} + +static int mtd_otp_nvmem_add(struct mtd_info *mtd) +{ + struct nvmem_device *nvmem; + ssize_t size; + int err; + + if (mtd->_get_user_prot_info && mtd->_read_user_prot_reg) { + size = mtd_otp_size(mtd, true); + if (size < 0) + return size; + + if (size > 0) { + nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size, + mtd_nvmem_user_otp_reg_read); + if (IS_ERR(nvmem)) { + dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n"); + return PTR_ERR(nvmem); + } + mtd->otp_user_nvmem = nvmem; + } + } + + if (mtd->_get_fact_prot_info && mtd->_read_fact_prot_reg) { + size = mtd_otp_size(mtd, false); + if (size < 0) { + err = size; + goto err; + } + + if (size > 0) { + nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size, + mtd_nvmem_fact_otp_reg_read); + if (IS_ERR(nvmem)) { + dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n"); + err = PTR_ERR(nvmem); + goto err; + } + mtd->otp_factory_nvmem = nvmem; + } + } + + return 0; + +err: + if (mtd->otp_user_nvmem) + nvmem_unregister(mtd->otp_user_nvmem); + return err; +} + /** * mtd_device_parse_register - parse partitions and register an MTD device. * @@ -852,6 +996,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, register_reboot_notifier(&mtd->reboot_notifier); } + ret = mtd_otp_nvmem_add(mtd); + out: if (ret && device_is_registered(&mtd->dev)) del_mtd_device(mtd); @@ -873,6 +1019,12 @@ int mtd_device_unregister(struct mtd_info *master) if (master->_reboot) unregister_reboot_notifier(&master->reboot_notifier); + if (master->otp_user_nvmem) + nvmem_unregister(master->otp_user_nvmem); + + if (master->otp_factory_nvmem) + nvmem_unregister(master->otp_factory_nvmem); + err = del_mtd_partitions(master); if (err) return err; diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 862c4a889234..227df24387df 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -401,10 +401,8 @@ static int __init mtdoops_init(void) cxt->mtd_index = mtd_index; cxt->oops_buf = vmalloc(record_size); - if (!cxt->oops_buf) { - printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n"); + if (!cxt->oops_buf) return -ENOMEM; - } memset(cxt->oops_buf, 0xff, record_size); cxt->oops_buf_busy = 0; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 665fd9020b76..04af12b66110 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -212,15 +212,14 @@ out_register: return child; } -static ssize_t mtd_partition_offset_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t offset_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%lld\n", mtd->part.offset); + return sysfs_emit(buf, "%lld\n", mtd->part.offset); } - -static DEVICE_ATTR(offset, S_IRUGO, mtd_partition_offset_show, NULL); +static DEVICE_ATTR_RO(offset); /* mtd partition offset */ static const struct attribute *mtd_partition_attrs[] = { &dev_attr_offset.attr, diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 6e15f424b071..f3276ee9e4fe 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1634,10 +1634,8 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc, } nand = devm_kzalloc(nc->dev, struct_size(nand, cs, numcs), GFP_KERNEL); - if (!nand) { - dev_err(nc->dev, "Failed to allocate NAND object\n"); + if (!nand) return ERR_PTR(-ENOMEM); - } nand->numcs = numcs; diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 923a9e236fcf..ea953e31933e 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1972,10 +1972,8 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, sunxi_nand = devm_kzalloc(dev, struct_size(sunxi_nand, sels, nsels), GFP_KERNEL); - if (!sunxi_nand) { - dev_err(dev, "could not allocate chip\n"); + if (!sunxi_nand) return -ENOMEM; - } sunxi_nand->nsels = nsels; diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index bcd0094f172d..913db0dd6a8d 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -619,7 +619,6 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) return BLOCK_NIL; } //printk("Restarting scan\n"); - lastEUN = BLOCK_NIL; continue; } diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 444a77bb7692..75e86ed3e678 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -188,17 +188,14 @@ device is already correct. /* memory alloc */ nftl->EUNtable = kmalloc_array(nftl->nb_blocks, sizeof(u16), GFP_KERNEL); - if (!nftl->EUNtable) { - printk(KERN_NOTICE "NFTL: allocation of EUNtable failed\n"); + if (!nftl->EUNtable) return -ENOMEM; - } nftl->ReplUnitTable = kmalloc_array(nftl->nb_blocks, sizeof(u16), GFP_KERNEL); if (!nftl->ReplUnitTable) { kfree(nftl->EUNtable); - printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n"); return -ENOMEM; } @@ -269,7 +266,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL); if (!buf) - return -1; + return -ENOMEM; ret = -1; for (i = 0; i < len; i += SECTORSIZE) { diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index 9babe678c41b..337ea8b9a4c3 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -115,7 +115,7 @@ config MTD_AFS_PARTS config MTD_PARSER_TRX tristate "Parser for TRX format partitions" - depends on MTD && (BCM47XX || ARCH_BCM_5301X || COMPILE_TEST) + depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || COMPILE_TEST) help TRX is a firmware format used by Broadcom on their devices. It may contain up to 3/4 partitions (depending on the version). diff --git a/drivers/mtd/parsers/parser_trx.c b/drivers/mtd/parsers/parser_trx.c index 8541182134d4..4814cf218e17 100644 --- a/drivers/mtd/parsers/parser_trx.c +++ b/drivers/mtd/parsers/parser_trx.c @@ -51,13 +51,20 @@ static int parser_trx_parse(struct mtd_info *mtd, const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { + struct device_node *np = mtd_get_of_node(mtd); struct mtd_partition *parts; struct mtd_partition *part; struct trx_header trx; size_t bytes_read; uint8_t curr_part = 0, i = 0; + uint32_t trx_magic = TRX_MAGIC; int err; + /* Get different magic from device tree if specified */ + err = of_property_read_u32(np, "brcm,trx-magic", &trx_magic); + if (err != 0 && err != -EINVAL) + pr_err("failed to parse \"brcm,trx-magic\" DT attribute, using default: %d\n", err); + parts = kcalloc(TRX_PARSER_MAX_PARTS, sizeof(struct mtd_partition), GFP_KERNEL); if (!parts) @@ -70,7 +77,7 @@ static int parser_trx_parse(struct mtd_info *mtd, return err; } - if (trx.magic != TRX_MAGIC) { + if (trx.magic != trx_magic) { kfree(parts); return -ENOENT; } diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c index d9083308f6ba..06a818cd2433 100644 --- a/drivers/mtd/parsers/qcomsmempart.c +++ b/drivers/mtd/parsers/qcomsmempart.c @@ -159,6 +159,15 @@ out_free_parts: return ret; } +static void parse_qcomsmem_cleanup(const struct mtd_partition *pparts, + int nr_parts) +{ + int i; + + for (i = 0; i < nr_parts; i++) + kfree(pparts[i].name); +} + static const struct of_device_id qcomsmem_of_match_table[] = { { .compatible = "qcom,smem-part" }, {}, @@ -167,6 +176,7 @@ MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table); static struct mtd_part_parser mtd_parser_qcomsmem = { .parse_fn = parse_qcomsmem_part, + .cleanup = parse_qcomsmem_cleanup, .name = "qcomsmem", .of_match_table = qcomsmem_of_match_table, }; diff --git a/drivers/mtd/parsers/redboot.c b/drivers/mtd/parsers/redboot.c index 91146bdc4713..feb44a573d44 100644 --- a/drivers/mtd/parsers/redboot.c +++ b/drivers/mtd/parsers/redboot.c @@ -17,15 +17,15 @@ #include <linux/module.h> struct fis_image_desc { - unsigned char name[16]; // Null terminated name - uint32_t flash_base; // Address within FLASH of image - uint32_t mem_base; // Address in memory where it executes - uint32_t size; // Length of image - uint32_t entry_point; // Execution entry point - uint32_t data_length; // Length of actual data - unsigned char _pad[256-(16+7*sizeof(uint32_t))]; - uint32_t desc_cksum; // Checksum over image descriptor - uint32_t file_cksum; // Checksum over image data + unsigned char name[16]; // Null terminated name + u32 flash_base; // Address within FLASH of image + u32 mem_base; // Address in memory where it executes + u32 size; // Length of image + u32 entry_point; // Execution entry point + u32 data_length; // Length of actual data + unsigned char _pad[256 - (16 + 7 * sizeof(u32))]; + u32 desc_cksum; // Checksum over image descriptor + u32 file_cksum; // Checksum over image data }; struct fis_list { @@ -45,6 +45,7 @@ static inline int redboot_checksum(struct fis_image_desc *img) static void parse_redboot_of(struct mtd_info *master) { struct device_node *np; + struct device_node *npart; u32 dirblock; int ret; @@ -52,7 +53,11 @@ static void parse_redboot_of(struct mtd_info *master) if (!np) return; - ret = of_property_read_u32(np, "fis-index-block", &dirblock); + npart = of_get_child_by_name(np, "partitions"); + if (!npart) + return; + + ret = of_property_read_u32(npart, "fis-index-block", &dirblock); if (ret) return; @@ -85,12 +90,12 @@ static int parse_redboot_partitions(struct mtd_info *master, parse_redboot_of(master); - if ( directory < 0 ) { + if (directory < 0) { offset = master->size + directory * master->erasesize; while (mtd_block_isbad(master, offset)) { if (!offset) { - nogood: - printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n"); +nogood: + pr_notice("Failed to find a non-bad block to check for RedBoot partition table\n"); return -EIO; } offset -= master->erasesize; @@ -108,8 +113,8 @@ static int parse_redboot_partitions(struct mtd_info *master, if (!buf) return -ENOMEM; - printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n", - master->name, offset); + pr_notice("Searching for RedBoot partition table in %s at offset 0x%lx\n", + master->name, offset); ret = mtd_read(master, offset, master->erasesize, &retlen, (void *)buf); @@ -145,14 +150,13 @@ static int parse_redboot_partitions(struct mtd_info *master, && swab32(buf[i].size) < master->erasesize)) { int j; /* Update numslots based on actual FIS directory size */ - numslots = swab32(buf[i].size) / sizeof (struct fis_image_desc); + numslots = swab32(buf[i].size) / sizeof(struct fis_image_desc); for (j = 0; j < numslots; ++j) { - /* A single 0xff denotes a deleted entry. * Two of them in a row is the end of the table. */ if (buf[j].name[0] == 0xff) { - if (buf[j].name[1] == 0xff) { + if (buf[j].name[1] == 0xff) { break; } else { continue; @@ -179,8 +183,8 @@ static int parse_redboot_partitions(struct mtd_info *master, } if (i == numslots) { /* Didn't find it */ - printk(KERN_NOTICE "No RedBoot partition table detected in %s\n", - master->name); + pr_notice("No RedBoot partition table detected in %s\n", + master->name); ret = 0; goto out; } @@ -199,7 +203,7 @@ static int parse_redboot_partitions(struct mtd_info *master, break; new_fl = kmalloc(sizeof(struct fis_list), GFP_KERNEL); - namelen += strlen(buf[i].name)+1; + namelen += strlen(buf[i].name) + 1; if (!new_fl) { ret = -ENOMEM; goto out; @@ -208,13 +212,13 @@ static int parse_redboot_partitions(struct mtd_info *master, if (data && data->origin) buf[i].flash_base -= data->origin; else - buf[i].flash_base &= master->size-1; + buf[i].flash_base &= master->size - 1; /* I'm sure the JFFS2 code has done me permanent damage. * I now think the following is _normal_ */ prev = &fl; - while(*prev && (*prev)->img->flash_base < new_fl->img->flash_base) + while (*prev && (*prev)->img->flash_base < new_fl->img->flash_base) prev = &(*prev)->next; new_fl->next = *prev; *prev = new_fl; @@ -234,7 +238,7 @@ static int parse_redboot_partitions(struct mtd_info *master, } } #endif - parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL); + parts = kzalloc(sizeof(*parts) * nrparts + nulllen + namelen, GFP_KERNEL); if (!parts) { ret = -ENOMEM; @@ -243,23 +247,22 @@ static int parse_redboot_partitions(struct mtd_info *master, nullname = (char *)&parts[nrparts]; #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED - if (nulllen > 0) { + if (nulllen > 0) strcpy(nullname, nullstring); - } #endif names = nullname + nulllen; - i=0; + i = 0; #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED if (fl->img->flash_base) { - parts[0].name = nullname; - parts[0].size = fl->img->flash_base; - parts[0].offset = 0; + parts[0].name = nullname; + parts[0].size = fl->img->flash_base; + parts[0].offset = 0; i++; } #endif - for ( ; i<nrparts; i++) { + for ( ; i < nrparts; i++) { parts[i].size = fl->img->size; parts[i].offset = fl->img->flash_base; parts[i].name = names; @@ -267,17 +270,17 @@ static int parse_redboot_partitions(struct mtd_info *master, strcpy(names, fl->img->name); #ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY if (!memcmp(names, "RedBoot", 8) || - !memcmp(names, "RedBoot config", 15) || - !memcmp(names, "FIS directory", 14)) { + !memcmp(names, "RedBoot config", 15) || + !memcmp(names, "FIS directory", 14)) { parts[i].mask_flags = MTD_WRITEABLE; } #endif - names += strlen(names)+1; + names += strlen(names) + 1; #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED - if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { + if (fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { i++; - parts[i].offset = parts[i-1].size + parts[i-1].offset; + parts[i].offset = parts[i - 1].size + parts[i - 1].offset; parts[i].size = fl->next->img->flash_base - parts[i].offset; parts[i].name = nullname; } @@ -291,6 +294,7 @@ static int parse_redboot_partitions(struct mtd_info *master, out: while (fl) { struct fis_list *old = fl; + fl = fl->next; kfree(old); } diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index cce3bf6f99b4..6e0d5ce9b010 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -192,11 +192,8 @@ static int scan_header(struct partition *part) part->sector_map = vmalloc(array_size(sizeof(u_long), part->sector_count)); - if (!part->sector_map) { - printk(KERN_ERR PREFIX "'%s': unable to allocate memory for " - "sector map", part->mbd.mtd->name); + if (!part->sector_map) goto err; - } for (i=0; i<part->sector_count; i++) part->sector_map[i] = -1; diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 4d1ae25507ab..0cff2cda1b5a 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -265,7 +265,8 @@ static int sm_read_sector(struct sm_ftl *ftl, again: if (try++) { /* Avoid infinite recursion on CIS reads, sm_recheck_media - won't help anyway */ + * won't help anyway + */ if (zone == 0 && block == ftl->cis_block && boffset == ftl->cis_boffset) return ret; @@ -276,7 +277,8 @@ again: } /* Unfortunately, oob read will _always_ succeed, - despite card removal..... */ + * despite card removal..... + */ ret = mtd_read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops); /* Test for unknown errors */ @@ -411,9 +413,10 @@ restart: /* If write fails. try to erase the block */ /* This is safe, because we never write in blocks - that contain valuable data. - This is intended to repair block that are marked - as erased, but that isn't fully erased*/ + * that contain valuable data. + * This is intended to repair block that are marked + * as erased, but that isn't fully erased + */ if (sm_erase_block(ftl, zone, block, 0)) return -EIO; @@ -448,7 +451,8 @@ static void sm_mark_block_bad(struct sm_ftl *ftl, int zone, int block) /* We aren't checking the return value, because we don't care */ /* This also fails on fake xD cards, but I guess these won't expose - any bad blocks till fail completely */ + * any bad blocks till fail completely + */ for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE) sm_write_sector(ftl, zone, block, boffset, NULL, &oob); } @@ -505,7 +509,8 @@ static int sm_check_block(struct sm_ftl *ftl, int zone, int block) /* First just check that block doesn't look fishy */ /* Only blocks that are valid or are sliced in two parts, are - accepted */ + * accepted + */ for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE) { @@ -554,7 +559,8 @@ static const uint8_t cis_signature[] = { 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20 }; /* Find out media parameters. - * This ideally has to be based on nand id, but for now device size is enough */ + * This ideally has to be based on nand id, but for now device size is enough + */ static int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd) { int i; @@ -607,7 +613,8 @@ static int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd) } /* Minimum xD size is 16MiB. Also, all xD cards have standard zone - sizes. SmartMedia cards exist up to 128 MiB and have same layout*/ + * sizes. SmartMedia cards exist up to 128 MiB and have same layout + */ if (size_in_megs >= 16) { ftl->zone_count = size_in_megs / 16; ftl->zone_size = 1024; @@ -782,7 +789,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) } /* Test to see if block is erased. It is enough to test - first sector, because erase happens in one shot */ + * first sector, because erase happens in one shot + */ if (sm_block_erased(&oob)) { kfifo_in(&zone->free_sectors, (unsigned char *)&block, 2); @@ -792,7 +800,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) /* If block is marked as bad, skip it */ /* This assumes we can trust first sector*/ /* However the way the block valid status is defined, ensures - very low probability of failure here */ + * very low probability of failure here + */ if (!sm_block_valid(&oob)) { dbg("PH %04d <-> <marked bad>", block); continue; @@ -803,7 +812,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) /* Invalid LBA means that block is damaged. */ /* We can try to erase it, or mark it as bad, but - lets leave that to recovery application */ + * lets leave that to recovery application + */ if (lba == -2 || lba >= ftl->max_lba) { dbg("PH %04d <-> LBA %04d(bad)", block, lba); continue; @@ -811,7 +821,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) /* If there is no collision, - just put the sector in the FTL table */ + * just put the sector in the FTL table + */ if (zone->lba_to_phys_table[lba] < 0) { dbg_verbose("PH %04d <-> LBA %04d", block, lba); zone->lba_to_phys_table[lba] = block; @@ -834,9 +845,9 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) } /* If both blocks are valid and share same LBA, it means that - they hold different versions of same data. It not - known which is more recent, thus just erase one of them - */ + * they hold different versions of same data. It not + * known which is more recent, thus just erase one of them + */ sm_printk("both blocks are valid, erasing the later"); sm_erase_block(ftl, zone_num, block, 1); } @@ -845,7 +856,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) zone->initialized = 1; /* No free sectors, means that the zone is heavily damaged, write won't - work, but it can still can be (partially) read */ + * work, but it can still can be (partially) read + */ if (!kfifo_len(&zone->free_sectors)) { sm_printk("no free blocks in zone %d", zone_num); return 0; @@ -952,8 +964,9 @@ restart: /* If there are no spare blocks, */ /* we could still continue by erasing/writing the current block, - but for such worn out media it doesn't worth the trouble, - and the dangers */ + * but for such worn out media it doesn't worth the trouble, + * and the dangers + */ if (kfifo_out(&zone->free_sectors, (unsigned char *)&write_sector, 2) != 2) { dbg("no free sectors for write!"); diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index c71daa89bfce..532997e10e29 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -506,7 +506,6 @@ static int __init mtd_oobtest_init(void) err = mtd_write_oob(mtd, addr0, &ops); if (err) { pr_info("error occurred as expected\n"); - err = 0; } else { pr_err("error: can write past end of OOB\n"); errcnt += 1; @@ -529,7 +528,6 @@ static int __init mtd_oobtest_init(void) if (err) { pr_info("error occurred as expected\n"); - err = 0; } else { pr_err("error: can read past end of OOB\n"); errcnt += 1; @@ -553,7 +551,6 @@ static int __init mtd_oobtest_init(void) err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); - err = 0; } else { pr_err("error: wrote past end of device\n"); errcnt += 1; @@ -576,7 +573,6 @@ static int __init mtd_oobtest_init(void) if (err) { pr_info("error occurred as expected\n"); - err = 0; } else { pr_err("error: read past end of device\n"); errcnt += 1; @@ -600,7 +596,6 @@ static int __init mtd_oobtest_init(void) err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); - err = 0; } else { pr_err("error: wrote past end of device\n"); errcnt += 1; @@ -623,7 +618,6 @@ static int __init mtd_oobtest_init(void) if (err) { pr_info("error occurred as expected\n"); - err = 0; } else { pr_err("error: read past end of device\n"); errcnt += 1; @@ -701,6 +695,7 @@ static int __init mtd_oobtest_init(void) (long long)addr); errcnt += 1; if (errcnt > 1000) { + err = -EINVAL; pr_err("error: too many errors\n"); goto out; } diff --git a/drivers/mtd/tests/torturetest.c b/drivers/mtd/tests/torturetest.c index 6787ac5471a9..841689b4d86d 100644 --- a/drivers/mtd/tests/torturetest.c +++ b/drivers/mtd/tests/torturetest.c @@ -230,8 +230,6 @@ static int __init tort_init(void) if (!bad_ebs) goto out_check_buf; - err = 0; - /* Initialize patterns */ memset(patt_FF, 0xFF, mtd->erasesize); for (i = 0; i < mtd->erasesize / pgsize; i++) { diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index bca671ff4e54..62d363a399d3 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -789,7 +789,9 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->reg_write = config->reg_write; nvmem->keepout = config->keepout; nvmem->nkeepout = config->nkeepout; - if (!config->no_of_node) + if (config->of_node) + nvmem->dev.of_node = config->of_node; + else if (!config->no_of_node) nvmem->dev.of_node = config->dev->of_node; switch (config->id) { |