diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-13 11:25:54 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-13 11:25:54 -0800 |
commit | ac53b2e053fffc74372da94e734b92f37e70d32c (patch) | |
tree | cda82af0fcded5d230e9f56104d3988b7a75c8aa /drivers/mtd/mtdpart.c | |
parent | cf09112d160e6db21ff8427ce696f819b957423b (diff) | |
parent | 9146cbd52b11d4ade62dba8f238ec5e421c3fa2b (diff) |
Merge tag 'for-linus-20160112' of git://git.infradead.org/linux-mtd
Pull MTD updates from Brian Norris:
"Generic MTD:
- populate the MTD device 'of_node' field (and get a proper 'of_node'
symlink in sysfs)
This yielded some new helper functions, and changes across a
variety of drivers
- partitioning cleanups, to prepare for better device-tree based
partitioning in the future
Eliminate a lot of boilerplate for drivers that want to use
OF-based partition parsing
The DT bindings for this didn't settle yet, so most non-cleanup
portions are deferred for a future release
NAND:
- embed a struct mtd_info inside struct nand_chip
This is really long overdue; too many drivers have to do the same
silly boilerplate to allocate and link up two "independent"
structs, when in fact, everyone is assuming there is an exact 1:1
relationship between a NAND chips struct and its underlying MTD.
This aids improved helpers and should make certain abstractions
easier in the future.
Also causes a lot of churn, helped along by some automated code
transformations
- add more core support for detecting (and "correcting") bitflips in
erased pages; requires opt-in by drivers, but at least we kill a
few bad implementations and hopefully stave off future ones
- pxa3xx_nand: cleanups, a few fixes, and PM improvements
- new JZ4780 NAND driver
SPI NOR:
- provide default erase function, for controllers that just want to
send the SECTOR_ERASE command directly
- fix some module auto-loading issues with device tree
("jedec,spi-nor")
- error handling fixes
- new Mediatek QSPI flash driver
Other:
- cfi: force valid geometry Kconfig (finally!)
This one used to trip up randconfigs occasionally, since bots
aren't deterred by big scary "advanced configuration" menus
More? Probably. See the commit logs"
* tag 'for-linus-20160112' of git://git.infradead.org/linux-mtd: (168 commits)
mtd: jz4780_nand: replace if/else blocks with switch/case
mtd: nand: jz4780: Update ecc correction error codes
mtd: nandsim: use nand_get_controller_data()
mtd: jz4780_nand: remove useless mtd->priv = chip assignment
staging: mt29f_spinand: make use of nand_set/get_controller_data() helpers
mtd: nand: make use of nand_set/get_controller_data() helpers
ARM: make use of nand_set/get_controller_data() helpers
mtd: nand: add helpers to access ->priv
mtd: nand: jz4780: driver for NAND devices on JZ4780 SoCs
mtd: nand: jz4740: remove custom 'erased check' implementation
mtd: nand: diskonchip: remove custom 'erased check' implementation
mtd: nand: davinci: remove custom 'erased check' implementation
mtd: nand: use nand_check_erased_ecc_chunk in default ECC read functions
mtd: nand: return consistent error codes in ecc.correct() implementations
doc: dt: mtd: new binding for jz4780-{nand,bch}
mtd: cfi_cmdset_0001: fixing memory leak and handling failed kmalloc
mtd: spi-nor: wait until lock/unlock operations are ready
mtd: tests: consolidate kmalloc/memset 0 call to kzalloc
jffs2: use to_delayed_work
mtd: nand: assign reasonable default name for NAND drivers
...
Diffstat (limited to 'drivers/mtd/mtdpart.c')
-rw-r--r-- | drivers/mtd/mtdpart.c | 133 |
1 files changed, 87 insertions, 46 deletions
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index f8ba153f63bf..10bf304027dd 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -48,9 +48,12 @@ struct mtd_part { /* * Given a pointer to the MTD object in the mtd_part structure, we can retrieve - * the pointer to that structure with this macro. + * the pointer to that structure. */ -#define PART(x) ((struct mtd_part *)(x)) +static inline struct mtd_part *mtd_to_part(const struct mtd_info *mtd) +{ + return container_of(mtd, struct mtd_part, mtd); +} /* @@ -61,7 +64,7 @@ struct mtd_part { static int part_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); struct mtd_ecc_stats stats; int res; @@ -80,7 +83,7 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len, static int part_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_point(part->master, from + part->offset, len, retlen, virt, phys); @@ -88,7 +91,7 @@ static int part_point(struct mtd_info *mtd, loff_t from, size_t len, static int part_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_unpoint(part->master, from + part->offset, len); } @@ -98,7 +101,7 @@ static unsigned long part_get_unmapped_area(struct mtd_info *mtd, unsigned long offset, unsigned long flags) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); offset += part->offset; return part->master->_get_unmapped_area(part->master, len, offset, @@ -108,7 +111,7 @@ static unsigned long part_get_unmapped_area(struct mtd_info *mtd, static int part_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); int res; if (from >= mtd->size) @@ -146,7 +149,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_read_user_prot_reg(part->master, from, len, retlen, buf); } @@ -154,7 +157,7 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from, static int part_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, struct otp_info *buf) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_get_user_prot_info(part->master, len, retlen, buf); } @@ -162,7 +165,7 @@ static int part_get_user_prot_info(struct mtd_info *mtd, size_t len, static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_read_fact_prot_reg(part->master, from, len, retlen, buf); } @@ -170,7 +173,7 @@ static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, struct otp_info *buf) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_get_fact_prot_info(part->master, len, retlen, buf); } @@ -178,7 +181,7 @@ static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len, static int part_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_write(part->master, to + part->offset, len, retlen, buf); } @@ -186,7 +189,7 @@ static int part_write(struct mtd_info *mtd, loff_t to, size_t len, static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_panic_write(part->master, to + part->offset, len, retlen, buf); } @@ -194,7 +197,7 @@ static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len, static int part_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); if (to >= mtd->size) return -EINVAL; @@ -206,7 +209,7 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to, static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_write_user_prot_reg(part->master, from, len, retlen, buf); } @@ -214,21 +217,21 @@ static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from, static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_lock_user_prot_reg(part->master, from, len); } static int part_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_writev(part->master, vecs, count, to + part->offset, retlen); } static int part_erase(struct mtd_info *mtd, struct erase_info *instr) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); int ret; instr->addr += part->offset; @@ -244,7 +247,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr) void mtd_erase_callback(struct erase_info *instr) { if (instr->mtd->_erase == part_erase) { - struct mtd_part *part = PART(instr->mtd); + struct mtd_part *part = mtd_to_part(instr->mtd); if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) instr->fail_addr -= part->offset; @@ -257,57 +260,57 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback); static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_lock(part->master, ofs + part->offset, len); } static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_unlock(part->master, ofs + part->offset, len); } static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_is_locked(part->master, ofs + part->offset, len); } static void part_sync(struct mtd_info *mtd) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); part->master->_sync(part->master); } static int part_suspend(struct mtd_info *mtd) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return part->master->_suspend(part->master); } static void part_resume(struct mtd_info *mtd) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); part->master->_resume(part->master); } static int part_block_isreserved(struct mtd_info *mtd, loff_t ofs) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); ofs += part->offset; return part->master->_block_isreserved(part->master, ofs); } static int part_block_isbad(struct mtd_info *mtd, loff_t ofs) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); ofs += part->offset; return part->master->_block_isbad(part->master, ofs); } static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) { - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); int res; ofs += part->offset; @@ -558,7 +561,7 @@ static ssize_t mtd_partition_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mtd_info *mtd = dev_get_drvdata(dev); - struct mtd_part *part = PART(mtd); + struct mtd_part *part = mtd_to_part(mtd); return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset); } @@ -596,11 +599,10 @@ int mtd_add_partition(struct mtd_info *master, const char *name, if (length <= 0) return -EINVAL; + memset(&part, 0, sizeof(part)); part.name = name; part.size = length; part.offset = offset; - part.mask_flags = 0; - part.ecclayout = NULL; new = allocate_partition(master, &part, -1, offset); if (IS_ERR(new)) @@ -685,7 +687,7 @@ int add_mtd_partitions(struct mtd_info *master, static DEFINE_SPINLOCK(part_parser_lock); static LIST_HEAD(part_parsers); -static struct mtd_part_parser *get_partition_parser(const char *name) +static struct mtd_part_parser *mtd_part_parser_get(const char *name) { struct mtd_part_parser *p, *ret = NULL; @@ -702,15 +704,35 @@ static struct mtd_part_parser *get_partition_parser(const char *name) return ret; } -#define put_partition_parser(p) do { module_put((p)->owner); } while (0) +static inline void mtd_part_parser_put(const struct mtd_part_parser *p) +{ + module_put(p->owner); +} + +/* + * Many partition parsers just expected the core to kfree() all their data in + * one chunk. Do that by default. + */ +static void mtd_part_parser_cleanup_default(const struct mtd_partition *pparts, + int nr_parts) +{ + kfree(pparts); +} -void register_mtd_parser(struct mtd_part_parser *p) +int __register_mtd_parser(struct mtd_part_parser *p, struct module *owner) { + p->owner = owner; + + if (!p->cleanup) + p->cleanup = &mtd_part_parser_cleanup_default; + spin_lock(&part_parser_lock); list_add(&p->list, &part_parsers); spin_unlock(&part_parser_lock); + + return 0; } -EXPORT_SYMBOL_GPL(register_mtd_parser); +EXPORT_SYMBOL_GPL(__register_mtd_parser); void deregister_mtd_parser(struct mtd_part_parser *p) { @@ -734,7 +756,7 @@ static const char * const default_mtd_part_types[] = { * parse_mtd_partitions - parse MTD partitions * @master: the master partition (describes whole MTD device) * @types: names of partition parsers to try or %NULL - * @pparts: array of partitions found is returned here + * @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 @@ -746,12 +768,13 @@ static const char * const default_mtd_part_types[] = { * * This function may return: * o a negative error code in case of failure - * o zero if no partitions were found - * o a positive number of found partitions, in which case on exit @pparts will - * point to an array containing this number of &struct mtd_info objects. + * 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. */ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, - struct mtd_partition **pparts, + struct mtd_partitions *pparts, struct mtd_part_parser_data *data) { struct mtd_part_parser *parser; @@ -762,22 +785,24 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, for ( ; *types; types++) { pr_debug("%s: parsing partitions %s\n", master->name, *types); - parser = get_partition_parser(*types); + parser = mtd_part_parser_get(*types); if (!parser && !request_module("%s", *types)) - parser = get_partition_parser(*types); + parser = mtd_part_parser_get(*types); pr_debug("%s: got parser %s\n", master->name, parser ? parser->name : NULL); if (!parser) continue; - ret = (*parser->parse_fn)(master, pparts, data); + ret = (*parser->parse_fn)(master, &pparts->parts, data); pr_debug("%s: parser %s: %i\n", master->name, parser->name, ret); - put_partition_parser(parser); if (ret > 0) { printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", ret, parser->name, master->name); - return ret; + pparts->nr_parts = ret; + pparts->parser = parser; + return 0; } + mtd_part_parser_put(parser); /* * Stash the first error we see; only report it if no parser * succeeds @@ -788,6 +813,22 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, return err; } +void mtd_part_parser_cleanup(struct mtd_partitions *parts) +{ + const struct mtd_part_parser *parser; + + if (!parts) + return; + + parser = parts->parser; + if (parser) { + if (parser->cleanup) + parser->cleanup(parts->parts, parts->nr_parts); + + mtd_part_parser_put(parser); + } +} + int mtd_is_partition(const struct mtd_info *mtd) { struct mtd_part *part; @@ -811,6 +852,6 @@ uint64_t mtd_get_device_size(const struct mtd_info *mtd) if (!mtd_is_partition(mtd)) return mtd->size; - return PART(mtd)->master->size; + return mtd_to_part(mtd)->master->size; } EXPORT_SYMBOL_GPL(mtd_get_device_size); |