diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-class-mtd | 8 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mtd/partition.txt | 2 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.txt | 42 | ||||
-rw-r--r-- | drivers/mtd/bcm47xxpart.c | 29 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 62 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_probe.c | 42 | ||||
-rw-r--r-- | drivers/mtd/cmdlinepart.c | 5 | ||||
-rw-r--r-- | drivers/mtd/devices/docg3.c | 3 | ||||
-rw-r--r-- | drivers/mtd/devices/mtd_dataflash.c | 2 | ||||
-rw-r--r-- | drivers/mtd/inftlmount.c | 23 | ||||
-rw-r--r-- | drivers/mtd/maps/pismo.c | 1 | ||||
-rw-r--r-- | drivers/mtd/mtdcore.c | 24 | ||||
-rw-r--r-- | drivers/mtd/mtdcore.h | 1 | ||||
-rw-r--r-- | drivers/mtd/mtdpart.c | 44 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mtd/nftlmount.c | 23 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/Kconfig | 2 |
17 files changed, 225 insertions, 96 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-mtd b/Documentation/ABI/testing/sysfs-class-mtd index f34e592301d1..3bc7c0a95c92 100644 --- a/Documentation/ABI/testing/sysfs-class-mtd +++ b/Documentation/ABI/testing/sysfs-class-mtd @@ -232,3 +232,11 @@ Description: of the parent (another partition or a flash device) in bytes. This attribute is absent on flash devices, so it can be used to distinguish them from partitions. + +What: /sys/class/mtd/mtdX/oobavail +Date: April 2018 +KernelVersion: 4.16 +Contact: linux-mtd@lists.infradead.org +Description: + Number of bytes available for a client to place data into + the out of band area. diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt index 36f3b769a626..a8f382642ba9 100644 --- a/Documentation/devicetree/bindings/mtd/partition.txt +++ b/Documentation/devicetree/bindings/mtd/partition.txt @@ -14,7 +14,7 @@ method is used for a given flash device. To describe the method there should be a subnode of the flash device that is named 'partitions'. It must have a 'compatible' property, which is used to identify the method to use. -We currently only document a binding for fixed layouts. +Available bindings are listed in the "partitions" subdirectory. Fixed Partitions diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.txt b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.txt new file mode 100644 index 000000000000..1d61a029395e --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.txt @@ -0,0 +1,42 @@ +Broadcom BCM47xx Partitions +=========================== + +Broadcom is one of hardware manufacturers providing SoCs (BCM47xx) used in +home routers. Their BCM947xx boards using CFE bootloader have several partitions +without any on-flash partition table. On some devices their sizes and/or +meanings can also vary so fixed partitioning can't be used. + +Discovering partitions on these devices is possible thanks to having a special +header and/or magic signature at the beginning of each of them. They are also +block aligned which is important for determinig a size. + +Most of partitions use ASCII text based magic for determining a type. More +complex partitions (like TRX with its HDR0 magic) may include extra header +containing some details, including a length. + +A list of supported partitions includes: +1) Bootloader with Broadcom's CFE (Common Firmware Environment) +2) NVRAM with configuration/calibration data +3) Device manufacturer's data with some default values (e.g. SSIDs) +4) TRX firmware container which can hold up to 4 subpartitions +5) Backup TRX firmware used after failed upgrade + +As mentioned earlier, role of some partitions may depend on extra configuration. +For example both: main firmware and backup firmware use the same TRX format with +the same header. To distinguish currently used firmware a CFE's environment +variable "bootpartition" is used. + + +Devices using Broadcom partitions described above should should have flash node +with a subnode named "partitions" using following properties: + +Required properties: +- compatible : (required) must be "brcm,bcm947xx-cfe-partitions" + +Example: + +flash@0 { + partitions { + compatible = "brcm,bcm947xx-cfe-partitions"; + }; +}; diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index fe2581d9d882..0f93d2239352 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -186,6 +186,8 @@ static int bcm47xxpart_parse(struct mtd_info *master, /* TRX */ if (buf[0x000 / 4] == TRX_MAGIC) { struct trx_header *trx; + uint32_t last_subpart; + uint32_t trx_size; if (trx_num >= ARRAY_SIZE(trx_parts)) pr_warn("No enough space to store another TRX found at 0x%X\n", @@ -195,11 +197,23 @@ static int bcm47xxpart_parse(struct mtd_info *master, bcm47xxpart_add_part(&parts[curr_part++], "firmware", offset, 0); - /* Jump to the end of TRX */ + /* + * Try to find TRX size. The "length" field isn't fully + * reliable as it could be decreased to make CRC32 cover + * only part of TRX data. It's commonly used as checksum + * can't cover e.g. ever-changing rootfs partition. + * Use offsets as helpers for assuming min TRX size. + */ trx = (struct trx_header *)buf; - offset = roundup(offset + trx->length, blocksize); - /* Next loop iteration will increase the offset */ - offset -= blocksize; + last_subpart = max3(trx->offset[0], trx->offset[1], + trx->offset[2]); + trx_size = max(trx->length, last_subpart + blocksize); + + /* + * Skip the TRX data. Decrease offset by block size as + * the next loop iteration will increase it. + */ + offset += roundup(trx_size, blocksize) - blocksize; continue; } @@ -290,9 +304,16 @@ static int bcm47xxpart_parse(struct mtd_info *master, return curr_part; }; +static const struct of_device_id bcm47xxpart_of_match_table[] = { + { .compatible = "brcm,bcm947xx-cfe-partitions" }, + {}, +}; +MODULE_DEVICE_TABLE(of, bcm47xxpart_of_match_table); + static struct mtd_part_parser bcm47xxpart_mtd_parser = { .parse_fn = bcm47xxpart_parse, .name = "bcm47xxpart", + .of_match_table = bcm47xxpart_of_match_table, }; module_mtd_part_parser(bcm47xxpart_mtd_parser); diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 668e2cbc155b..78b69ccd0b65 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -42,10 +42,10 @@ #define AMD_BOOTLOC_BUG #define FORCE_WORD_WRITE 0 -#define MAX_WORD_RETRIES 3 +#define MAX_RETRIES 3 -#define SST49LF004B 0x0060 -#define SST49LF040B 0x0050 +#define SST49LF004B 0x0060 +#define SST49LF040B 0x0050 #define SST49LF008A 0x005a #define AT49BV6416 0x00d6 @@ -207,7 +207,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; if (cfi->cfiq->BufWriteTimeoutTyp) { - pr_debug("Using buffer write method\n" ); + pr_debug("Using buffer write method\n"); mtd->_write = cfi_amdstd_write_buffers; } } @@ -1562,7 +1562,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, * depending of the conditions. The ' + 1' is to avoid having a * timeout of 0 jiffies if HZ is smaller than 1000. */ - unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; + unsigned long uWriteTimeout = (HZ / 1000) + 1; int ret = 0; map_word oldd; int retry_cnt = 0; @@ -1577,7 +1577,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, } pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", - __func__, adr, datum.x[0] ); + __func__, adr, datum.x[0]); if (mode == FL_OTP_WRITE) otp_enter(map, chip, adr, map_bankwidth(map)); @@ -1643,10 +1643,10 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, /* Did we succeed? */ if (!chip_good(map, adr, datum)) { /* reset on all failures. */ - map_write( map, CMD(0xF0), chip->start ); + map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) + if (++retry_cnt <= MAX_RETRIES) goto retry; ret = -EIO; @@ -1821,7 +1821,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, datum = map_word_load(map, buf); pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", - __func__, adr, datum.x[0] ); + __func__, adr, datum.x[0]); XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); @@ -1879,7 +1879,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, if (time_after(jiffies, timeo) && !chip_ready(map, adr)) break; - if (chip_ready(map, adr)) { + if (chip_good(map, adr, datum)) { xip_enable(map, chip, adr); goto op_done; } @@ -2105,7 +2105,7 @@ retry: map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) + if (++retry_cnt <= MAX_RETRIES) goto retry; ret = -EIO; @@ -2240,6 +2240,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) unsigned long int adr; DECLARE_WAITQUEUE(wait, current); int ret = 0; + int retry_cnt = 0; adr = cfi->addr_unlock1; @@ -2251,12 +2252,13 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) } pr_debug("MTD %s(): ERASE 0x%.8lx\n", - __func__, chip->start ); + __func__, chip->start); XIP_INVAL_CACHED_RANGE(map, adr, map->size); ENABLE_VPP(map); xip_disable(map, chip, adr); + retry: cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -2292,12 +2294,13 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) chip->erase_suspended = 0; } - if (chip_ready(map, adr)) + if (chip_good(map, adr, map_word_ff(map))) break; if (time_after(jiffies, timeo)) { printk(KERN_WARNING "MTD %s(): software timeout\n", - __func__ ); + __func__); + ret = -EIO; break; } @@ -2305,12 +2308,15 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ - if (!chip_good(map, adr, map_word_ff(map))) { + if (ret) { /* reset on all failures. */ - map_write( map, CMD(0xF0), chip->start ); + map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ - ret = -EIO; + if (++retry_cnt <= MAX_RETRIES) { + ret = 0; + goto retry; + } } chip->state = FL_READY; @@ -2329,6 +2335,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long timeo = jiffies + HZ; DECLARE_WAITQUEUE(wait, current); int ret = 0; + int retry_cnt = 0; adr += chip->start; @@ -2340,12 +2347,13 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, } pr_debug("MTD %s(): ERASE 0x%.8lx\n", - __func__, adr ); + __func__, adr); XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); xip_disable(map, chip, adr); + retry: cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -2381,15 +2389,13 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->erase_suspended = 0; } - if (chip_ready(map, adr)) { - xip_enable(map, chip, adr); + if (chip_good(map, adr, map_word_ff(map))) break; - } if (time_after(jiffies, timeo)) { - xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", - __func__ ); + __func__); + ret = -EIO; break; } @@ -2397,15 +2403,19 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ - if (!chip_good(map, adr, map_word_ff(map))) { + if (ret) { /* reset on all failures. */ - map_write( map, CMD(0xF0), chip->start ); + map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ - ret = -EIO; + if (++retry_cnt <= MAX_RETRIES) { + ret = 0; + goto retry; + } } chip->state = FL_READY; + xip_enable(map, chip, adr); DISABLE_VPP(map); put_chip(map, chip, adr); mutex_unlock(&chip->mutex); diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index e8d0164498b0..cf426956454c 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -63,6 +63,30 @@ do { \ #endif +/* + * This fixup occurs immediately after reading the CFI structure and can affect + * the number of chips detected, unlike cfi_fixup, which occurs after an + * mtd_info structure has been created for the chip. + */ +struct cfi_early_fixup { + uint16_t mfr; + uint16_t id; + void (*fixup)(struct cfi_private *cfi); +}; + +static void cfi_early_fixup(struct cfi_private *cfi, + const struct cfi_early_fixup *fixups) +{ + const struct cfi_early_fixup *f; + + for (f = fixups; f->fixup; f++) { + if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) && + ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) { + f->fixup(cfi); + } + } +} + /* check for QRY. in: interleave,type,mode ret: table index, <0 for error @@ -151,6 +175,22 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, return 1; } +static void fixup_s70gl02gs_chips(struct cfi_private *cfi) +{ + /* + * S70GL02GS flash reports a single 256 MiB chip, but is really made up + * of two 128 MiB chips with 1024 sectors each. + */ + cfi->cfiq->DevSize = 27; + cfi->cfiq->EraseRegionInfo[0] = 0x20003ff; + pr_warn("Bad S70GL02GS CFI data; adjust to detect 2 chips\n"); +} + +static const struct cfi_early_fixup cfi_early_fixup_table[] = { + { CFI_MFR_AMD, 0x4801, fixup_s70gl02gs_chips }, + { }, +}; + static int __xipram cfi_chip_setup(struct map_info *map, struct cfi_private *cfi) { @@ -235,6 +275,8 @@ static int __xipram cfi_chip_setup(struct map_info *map, cfi_qry_mode_off(base, map, cfi); xip_allowed(base, map); + cfi_early_fixup(cfi, cfi_early_fixup_table); + printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank. Manufacturer ID %#08x Chip ID %#08x\n", map->name, cfi->interleave, cfi->device_type*8, base, map->bankwidth*8, cfi->mfr, cfi->id); diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index fbd5affc0acf..3ea44cff9b75 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -190,7 +190,10 @@ static struct mtd_partition * newpart(char *s, extra_mem = (unsigned char *)(parts + *num_parts); } - /* enter this partition (offset will be calculated later if it is zero at this point) */ + /* + * enter this partition (offset will be calculated later if it is + * OFFSET_CONTINUOUS at this point) + */ parts[this_part].size = size; parts[this_part].offset = offset; parts[this_part].mask_flags = mask_flags; diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index c594fe5eac08..802d8f159e90 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1470,8 +1470,7 @@ static struct docg3 *sysfs_dev2docg3(struct device *dev, struct device_attribute *attr) { int floor; - struct platform_device *pdev = to_platform_device(dev); - struct mtd_info **docg3_floors = platform_get_drvdata(pdev); + struct mtd_info **docg3_floors = dev_get_drvdata(dev); floor = attr->attr.name[1] - '0'; if (floor < 0 || floor >= DOC_MAX_NBFLOORS) diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index aaaeaae01e1d..3a6f450d1093 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -140,7 +140,7 @@ static int dataflash_waitready(struct spi_device *spi) if (status & (1 << 7)) /* RDY/nBSY */ return status; - msleep(3); + usleep_range(3000, 4000); } } diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index aab4f68bd36f..2d598412972d 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -334,28 +334,37 @@ static int memcmpb(void *a, int c, int n) static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, int len, int check_oob) { - u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize]; struct mtd_info *mtd = inftl->mbd.mtd; size_t retlen; - int i; + int i, ret; + u8 *buf; + + buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL); + if (!buf) + return -1; + ret = -1; for (i = 0; i < len; i += SECTORSIZE) { if (mtd_read(mtd, address, SECTORSIZE, &retlen, buf)) - return -1; + goto out; if (memcmpb(buf, 0xff, SECTORSIZE) != 0) - return -1; + goto out; if (check_oob) { if(inftl_read_oob(mtd, address, mtd->oobsize, &retlen, &buf[SECTORSIZE]) < 0) - return -1; + goto out; if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0) - return -1; + goto out; } address += SECTORSIZE; } - return 0; + ret = 0; + +out: + kfree(buf); + return ret; } /* diff --git a/drivers/mtd/maps/pismo.c b/drivers/mtd/maps/pismo.c index dc6df9abea0b..c065d7995c0a 100644 --- a/drivers/mtd/maps/pismo.c +++ b/drivers/mtd/maps/pismo.c @@ -265,7 +265,6 @@ MODULE_DEVICE_TABLE(i2c, pismo_id); static struct i2c_driver pismo_driver = { .driver = { .name = "pismo", - .owner = THIS_MODULE, }, .probe = pismo_probe, .remove = pismo_remove, diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 807d17d863b3..7b0d105627b1 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -210,6 +210,15 @@ static ssize_t mtd_oobsize_show(struct device *dev, } static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL); +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); +} +static DEVICE_ATTR(oobavail, S_IRUGO, mtd_oobavail_show, NULL); + static ssize_t mtd_numeraseregions_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -327,6 +336,7 @@ static struct attribute *mtd_attrs[] = { &dev_attr_writesize.attr, &dev_attr_subpagesize.attr, &dev_attr_oobsize.attr, + &dev_attr_oobavail.attr, &dev_attr_numeraseregions.attr, &dev_attr_name.attr, &dev_attr_ecc_strength.attr, @@ -690,7 +700,6 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, const struct mtd_partition *parts, int nr_parts) { - struct mtd_partitions parsed = { }; int ret; mtd_set_dev_defaults(mtd); @@ -702,13 +711,10 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, } /* Prefer parsed partitions over driver-provided fallback */ - ret = parse_mtd_partitions(mtd, types, &parsed, parser_data); - if (!ret && parsed.nr_parts) { - parts = parsed.parts; - nr_parts = parsed.nr_parts; - } - - if (nr_parts) + ret = parse_mtd_partitions(mtd, types, parser_data); + if (ret > 0) + ret = 0; + else if (nr_parts) ret = add_mtd_partitions(mtd, parts, nr_parts); else if (!device_is_registered(&mtd->dev)) ret = add_mtd_device(mtd); @@ -734,8 +740,6 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, } out: - /* Cleanup any parsed partitions */ - mtd_part_parser_cleanup(&parsed); if (ret && device_is_registered(&mtd->dev)) del_mtd_device(mtd); diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h index 37accfd0400e..9887bda317cd 100644 --- a/drivers/mtd/mtdcore.h +++ b/drivers/mtd/mtdcore.h @@ -15,7 +15,6 @@ int del_mtd_partitions(struct mtd_info *); struct mtd_partitions; int parse_mtd_partitions(struct mtd_info *master, const char * const *types, - struct mtd_partitions *pparts, struct mtd_part_parser_data *data); void mtd_part_parser_cleanup(struct mtd_partitions *parts); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 023516a63276..f8d3a015cdad 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -335,20 +335,7 @@ static inline void free_partition(struct mtd_part *p) */ static int mtd_parse_part(struct mtd_part *slave, const char *const *types) { - struct mtd_partitions parsed; - int err; - - err = parse_mtd_partitions(&slave->mtd, types, &parsed, NULL); - if (err) - return err; - else if (!parsed.nr_parts) - return -ENOENT; - - err = add_mtd_partitions(&slave->mtd, parsed.parts, parsed.nr_parts); - - mtd_part_parser_cleanup(&parsed); - - return err; + return parse_mtd_partitions(&slave->mtd, types, NULL); } static struct mtd_part *allocate_partition(struct mtd_info *parent, @@ -933,30 +920,27 @@ static int mtd_part_of_parse(struct mtd_info *master, } /** - * parse_mtd_partitions - parse MTD partitions + * parse_mtd_partitions - parse and register MTD partitions + * * @master: the master partition (describes whole MTD device) * @types: names of partition parsers to try or %NULL - * @pparts: info about partitions found is returned here * @data: MTD partition parser-specific data * - * This function tries to find partition on MTD device @master. It uses MTD - * partition parsers, specified in @types. However, if @types is %NULL, then - * the default list of parsers is used. The default list contains only the + * This function tries to find & register partitions on MTD device @master. It + * uses MTD partition parsers, specified in @types. However, if @types is %NULL, + * then the default list of parsers is used. The default list contains only the * "cmdlinepart" and "ofpart" parsers ATM. * Note: If there are more then one parser in @types, the kernel only takes the * partitions parsed out by the first parser. * * This function may return: * o a negative error code in case of failure - * o zero otherwise, and @pparts will describe the partitions, number of - * partitions, and the parser which parsed them. Caller must release - * resources with mtd_part_parser_cleanup() when finished with the returned - * data. + * o number of found partitions otherwise */ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, - struct mtd_partitions *pparts, struct mtd_part_parser_data *data) { + struct mtd_partitions pparts = { }; struct mtd_part_parser *parser; int ret, err = 0; @@ -970,7 +954,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, * handled in a separated function. */ if (!strcmp(*types, "ofpart")) { - ret = mtd_part_of_parse(master, pparts); + ret = mtd_part_of_parse(master, &pparts); } else { pr_debug("%s: parsing partitions %s\n", master->name, *types); @@ -981,13 +965,17 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, parser ? parser->name : NULL); if (!parser) continue; - ret = mtd_part_do_parse(parser, master, pparts, data); + ret = mtd_part_do_parse(parser, master, &pparts, data); if (ret <= 0) mtd_part_parser_put(parser); } /* Found partitions! */ - if (ret > 0) - return 0; + if (ret > 0) { + err = add_mtd_partitions(master, pparts.parts, + pparts.nr_parts); + mtd_part_parser_cleanup(&pparts); + return err ? err : pparts.nr_parts; + } /* * Stash the first error we see; only report it if no parser * succeeds diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 19a2b283fbbe..6871ff0fd300 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -46,7 +46,7 @@ config MTD_NAND_DENALI config MTD_NAND_DENALI_PCI tristate "Support Denali NAND controller on Intel Moorestown" select MTD_NAND_DENALI - depends on HAS_DMA && PCI + depends on PCI help Enable the driver for NAND flash on Intel Moorestown, using the Denali NAND controller core. @@ -152,7 +152,6 @@ config MTD_NAND_S3C2410_CLKSTOP config MTD_NAND_TANGO tristate "NAND Flash support for Tango chips" depends on ARCH_TANGO || COMPILE_TEST - depends on HAS_DMA help Enables the NAND Flash controller on Tango chips. @@ -285,7 +284,7 @@ config MTD_NAND_MARVELL tristate "NAND controller support on Marvell boards" depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \ COMPILE_TEST - depends on HAS_IOMEM && HAS_DMA + depends on HAS_IOMEM help This enables the NAND flash controller driver for Marvell boards, including: @@ -447,7 +446,6 @@ config MTD_NAND_SH_FLCTL tristate "Support for NAND on Renesas SuperH FLCTL" depends on SUPERH || COMPILE_TEST depends on HAS_IOMEM - depends on HAS_DMA help Several Renesas SuperH CPU has FLCTL. This option enables support for NAND Flash using FLCTL. @@ -515,7 +513,6 @@ config MTD_NAND_SUNXI config MTD_NAND_HISI504 tristate "Support for NAND controller on Hisilicon SoC Hip04" depends on ARCH_HISI || COMPILE_TEST - depends on HAS_DMA help Enables support for NAND controller on Hisilicon SoC Hip04. @@ -529,7 +526,6 @@ config MTD_NAND_QCOM config MTD_NAND_MTK tristate "Support for NAND controller on MTK SoCs" depends on ARCH_MEDIATEK || COMPILE_TEST - depends on HAS_DMA help Enables support for NAND controller on MTK SoCs. This controller is found on mt27xx, mt81xx, mt65xx SoCs. diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index a6fbfa4e5799..6281da3dadac 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -272,28 +272,37 @@ static int memcmpb(void *a, int c, int n) static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, int check_oob) { - u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize]; struct mtd_info *mtd = nftl->mbd.mtd; size_t retlen; - int i; + int i, ret; + u8 *buf; + + buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL); + if (!buf) + return -1; + ret = -1; for (i = 0; i < len; i += SECTORSIZE) { if (mtd_read(mtd, address, SECTORSIZE, &retlen, buf)) - return -1; + goto out; if (memcmpb(buf, 0xff, SECTORSIZE) != 0) - return -1; + goto out; if (check_oob) { if(nftl_read_oob(mtd, address, mtd->oobsize, &retlen, &buf[SECTORSIZE]) < 0) - return -1; + goto out; if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0) - return -1; + goto out; } address += SECTORSIZE; } - return 0; + ret = 0; + +out: + kfree(buf); + return ret; } /* NFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase Unit and diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 89da88e59121..c493b8230a38 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -71,7 +71,7 @@ config SPI_FSL_QUADSPI config SPI_HISI_SFC tristate "Hisilicon SPI-NOR Flash Controller(SFC)" depends on ARCH_HISI || COMPILE_TEST - depends on HAS_IOMEM && HAS_DMA + depends on HAS_IOMEM help This enables support for hisilicon SPI-NOR flash controller. |