diff options
Diffstat (limited to 'drivers/mtd/mtdcore.c')
| -rw-r--r-- | drivers/mtd/mtdcore.c | 75 |
1 files changed, 70 insertions, 5 deletions
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 724f917f91ba..64808493b4f5 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -384,14 +384,64 @@ EXPORT_SYMBOL_GPL(mtd_check_expert_analysis_mode); static struct dentry *dfs_dir_mtd; +static int mtd_ooblayout_show(struct seq_file *s, void *p, + int (*iter)(struct mtd_info *, int section, + struct mtd_oob_region *region)) +{ + struct mtd_info *mtd = s->private; + int section; + + for (section = 0;; section++) { + struct mtd_oob_region region; + int err; + + err = iter(mtd, section, ®ion); + if (err) { + if (err == -ERANGE) + break; + + return err; + } + + seq_printf(s, "%-3d %4u %4u\n", section, region.offset, + region.length); + } + + return 0; +} + +static int mtd_ooblayout_ecc_show(struct seq_file *s, void *p) +{ + return mtd_ooblayout_show(s, p, mtd_ooblayout_ecc); +} +DEFINE_SHOW_ATTRIBUTE(mtd_ooblayout_ecc); + +static int mtd_ooblayout_free_show(struct seq_file *s, void *p) +{ + return mtd_ooblayout_show(s, p, mtd_ooblayout_free); +} +DEFINE_SHOW_ATTRIBUTE(mtd_ooblayout_free); + static void mtd_debugfs_populate(struct mtd_info *mtd) { struct device *dev = &mtd->dev; + struct mtd_oob_region region; if (IS_ERR_OR_NULL(dfs_dir_mtd)) return; mtd->dbg.dfs_dir = debugfs_create_dir(dev_name(dev), dfs_dir_mtd); + if (IS_ERR_OR_NULL(mtd->dbg.dfs_dir)) + return; + + /* Create ooblayout files only if at least one region is present. */ + if (mtd_ooblayout_ecc(mtd, 0, ®ion) == 0) + debugfs_create_file("ooblayout_ecc", 0444, mtd->dbg.dfs_dir, + mtd, &mtd_ooblayout_ecc_fops); + + if (mtd_ooblayout_free(mtd, 0, ®ion) == 0) + debugfs_create_file("ooblayout_free", 0444, mtd->dbg.dfs_dir, + mtd, &mtd_ooblayout_free_fops); } #ifndef CONFIG_MMU @@ -741,7 +791,9 @@ int add_mtd_device(struct mtd_info *mtd) mtd->dev.type = &mtd_devtype; mtd->dev.class = &mtd_class; mtd->dev.devt = MTD_DEVT(i); - dev_set_name(&mtd->dev, "mtd%d", i); + error = dev_set_name(&mtd->dev, "mtd%d", i); + if (error) + goto fail_devname; dev_set_drvdata(&mtd->dev, mtd); mtd_check_of_node(mtd); of_node_get(mtd_get_of_node(mtd)); @@ -790,6 +842,7 @@ fail_nvmem_add: device_unregister(&mtd->dev); fail_added: of_node_put(mtd_get_of_node(mtd)); +fail_devname: idr_remove(&mtd_idr, i); fail_locked: mutex_unlock(&mtd_table_mutex); @@ -1053,7 +1106,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, const struct mtd_partition *parts, int nr_parts) { - int ret; + int ret, err; mtd_set_dev_defaults(mtd); @@ -1105,8 +1158,11 @@ out: nvmem_unregister(mtd->otp_factory_nvmem); } - if (ret && device_is_registered(&mtd->dev)) - del_mtd_device(mtd); + if (ret && device_is_registered(&mtd->dev)) { + err = del_mtd_device(mtd); + if (err) + pr_err("Error when deleting MTD device (%d)\n", err); + } return ret; } @@ -2333,6 +2389,7 @@ EXPORT_SYMBOL_GPL(mtd_block_isbad); int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct mtd_info *master = mtd_get_master(mtd); + loff_t moffs; int ret; if (!master->_block_markbad) @@ -2345,7 +2402,15 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize; - ret = master->_block_markbad(master, mtd_get_master_ofs(mtd, ofs)); + moffs = mtd_get_master_ofs(mtd, ofs); + + if (master->_block_isbad) { + ret = master->_block_isbad(master, moffs); + if (ret > 0) + return 0; + } + + ret = master->_block_markbad(master, moffs); if (ret) return ret; |
