diff options
Diffstat (limited to 'drivers/mtd/mtdcore.c')
-rw-r--r-- | drivers/mtd/mtdcore.c | 105 |
1 files changed, 104 insertions, 1 deletions
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index e3936b847c6b..d46e4adf6d2b 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -39,7 +39,6 @@ #include <linux/gfp.h> #include <linux/slab.h> #include <linux/reboot.h> -#include <linux/kconfig.h> #include <linux/leds.h> #include <linux/mtd/mtd.h> @@ -376,6 +375,110 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state, } /** + * mtd_wunit_to_pairing_info - get pairing information of a wunit + * @mtd: pointer to new MTD device info structure + * @wunit: write unit we are interested in + * @info: returned pairing information + * + * Retrieve pairing information associated to the wunit. + * This is mainly useful when dealing with MLC/TLC NANDs where pages can be + * paired together, and where programming a page may influence the page it is + * paired with. + * The notion of page is replaced by the term wunit (write-unit) to stay + * consistent with the ->writesize field. + * + * The @wunit argument can be extracted from an absolute offset using + * mtd_offset_to_wunit(). @info is filled with the pairing information attached + * to @wunit. + * + * From the pairing info the MTD user can find all the wunits paired with + * @wunit using the following loop: + * + * for (i = 0; i < mtd_pairing_groups(mtd); i++) { + * info.pair = i; + * mtd_pairing_info_to_wunit(mtd, &info); + * ... + * } + */ +int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit, + struct mtd_pairing_info *info) +{ + int npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd); + + if (wunit < 0 || wunit >= npairs) + return -EINVAL; + + if (mtd->pairing && mtd->pairing->get_info) + return mtd->pairing->get_info(mtd, wunit, info); + + info->group = 0; + info->pair = wunit; + + return 0; +} +EXPORT_SYMBOL_GPL(mtd_wunit_to_pairing_info); + +/** + * mtd_wunit_to_pairing_info - get wunit from pairing information + * @mtd: pointer to new MTD device info structure + * @info: pairing information struct + * + * Returns a positive number representing the wunit associated to the info + * struct, or a negative error code. + * + * This is the reverse of mtd_wunit_to_pairing_info(), and can help one to + * iterate over all wunits of a given pair (see mtd_wunit_to_pairing_info() + * doc). + * + * It can also be used to only program the first page of each pair (i.e. + * page attached to group 0), which allows one to use an MLC NAND in + * software-emulated SLC mode: + * + * info.group = 0; + * npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd); + * for (info.pair = 0; info.pair < npairs; info.pair++) { + * wunit = mtd_pairing_info_to_wunit(mtd, &info); + * mtd_write(mtd, mtd_wunit_to_offset(mtd, blkoffs, wunit), + * mtd->writesize, &retlen, buf + (i * mtd->writesize)); + * } + */ +int mtd_pairing_info_to_wunit(struct mtd_info *mtd, + const struct mtd_pairing_info *info) +{ + int ngroups = mtd_pairing_groups(mtd); + int npairs = mtd_wunit_per_eb(mtd) / ngroups; + + if (!info || info->pair < 0 || info->pair >= npairs || + info->group < 0 || info->group >= ngroups) + return -EINVAL; + + if (mtd->pairing && mtd->pairing->get_wunit) + return mtd->pairing->get_wunit(mtd, info); + + return info->pair; +} +EXPORT_SYMBOL_GPL(mtd_pairing_info_to_wunit); + +/** + * mtd_pairing_groups - get the number of pairing groups + * @mtd: pointer to new MTD device info structure + * + * Returns the number of pairing groups. + * + * This number is usually equal to the number of bits exposed by a single + * cell, and can be used in conjunction with mtd_pairing_info_to_wunit() + * to iterate over all pages of a given pair. + */ +int mtd_pairing_groups(struct mtd_info *mtd) +{ + if (!mtd->pairing || !mtd->pairing->ngroups) + return 1; + + return mtd->pairing->ngroups; +} +EXPORT_SYMBOL_GPL(mtd_pairing_groups); + +/** * add_mtd_device - register an MTD device * @mtd: pointer to new MTD device info structure * |