Merge tag '4.9/mtd-pairing-scheme' of github.com:linux-nand/linux

Introduction of the MTD pairing scheme concept.
This commit is contained in:
Brian Norris
2016-10-08 12:23:37 -07:00
3 changed files with 212 additions and 0 deletions

View File

@@ -375,6 +375,110 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
return NOTIFY_DONE;
}
/**
* 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

View File

@@ -409,6 +409,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.oobsize = master->oobsize;
slave->mtd.oobavail = master->oobavail;
slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.pairing = master->pairing;
slave->mtd.name = name;
slave->mtd.owner = master->owner;