aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Norris <computersforpeace@gmail.com>2016-10-08 15:23:37 -0400
committerBrian Norris <computersforpeace@gmail.com>2016-10-08 23:56:54 -0400
commit69db4aa44fdd8befc2eccd1313d841c5128c385c (patch)
tree1b84be76e9497231ed8027cf2a22b79fab64a87c
parentf5b88de284932def6850e976c18d25940c1b2c3d (diff)
parent477b0229ac9bc275f6f8d2c27a2d08b246fccd0e (diff)
Merge tag '4.9/mtd-pairing-scheme' of github.com:linux-nand/linux
Introduction of the MTD pairing scheme concept.
-rw-r--r--drivers/mtd/mtdcore.c104
-rw-r--r--drivers/mtd/mtdpart.c1
-rw-r--r--include/linux/mtd/mtd.h107
3 files changed, 212 insertions, 0 deletions
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index e3936b847c6b..4f270482cfd0 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -376,6 +376,110 @@ static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
376} 376}
377 377
378/** 378/**
379 * mtd_wunit_to_pairing_info - get pairing information of a wunit
380 * @mtd: pointer to new MTD device info structure
381 * @wunit: write unit we are interested in
382 * @info: returned pairing information
383 *
384 * Retrieve pairing information associated to the wunit.
385 * This is mainly useful when dealing with MLC/TLC NANDs where pages can be
386 * paired together, and where programming a page may influence the page it is
387 * paired with.
388 * The notion of page is replaced by the term wunit (write-unit) to stay
389 * consistent with the ->writesize field.
390 *
391 * The @wunit argument can be extracted from an absolute offset using
392 * mtd_offset_to_wunit(). @info is filled with the pairing information attached
393 * to @wunit.
394 *
395 * From the pairing info the MTD user can find all the wunits paired with
396 * @wunit using the following loop:
397 *
398 * for (i = 0; i < mtd_pairing_groups(mtd); i++) {
399 * info.pair = i;
400 * mtd_pairing_info_to_wunit(mtd, &info);
401 * ...
402 * }
403 */
404int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
405 struct mtd_pairing_info *info)
406{
407 int npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd);
408
409 if (wunit < 0 || wunit >= npairs)
410 return -EINVAL;
411
412 if (mtd->pairing && mtd->pairing->get_info)
413 return mtd->pairing->get_info(mtd, wunit, info);
414
415 info->group = 0;
416 info->pair = wunit;
417
418 return 0;
419}
420EXPORT_SYMBOL_GPL(mtd_wunit_to_pairing_info);
421
422/**
423 * mtd_wunit_to_pairing_info - get wunit from pairing information
424 * @mtd: pointer to new MTD device info structure
425 * @info: pairing information struct
426 *
427 * Returns a positive number representing the wunit associated to the info
428 * struct, or a negative error code.
429 *
430 * This is the reverse of mtd_wunit_to_pairing_info(), and can help one to
431 * iterate over all wunits of a given pair (see mtd_wunit_to_pairing_info()
432 * doc).
433 *
434 * It can also be used to only program the first page of each pair (i.e.
435 * page attached to group 0), which allows one to use an MLC NAND in
436 * software-emulated SLC mode:
437 *
438 * info.group = 0;
439 * npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd);
440 * for (info.pair = 0; info.pair < npairs; info.pair++) {
441 * wunit = mtd_pairing_info_to_wunit(mtd, &info);
442 * mtd_write(mtd, mtd_wunit_to_offset(mtd, blkoffs, wunit),
443 * mtd->writesize, &retlen, buf + (i * mtd->writesize));
444 * }
445 */
446int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
447 const struct mtd_pairing_info *info)
448{
449 int ngroups = mtd_pairing_groups(mtd);
450 int npairs = mtd_wunit_per_eb(mtd) / ngroups;
451
452 if (!info || info->pair < 0 || info->pair >= npairs ||
453 info->group < 0 || info->group >= ngroups)
454 return -EINVAL;
455
456 if (mtd->pairing && mtd->pairing->get_wunit)
457 return mtd->pairing->get_wunit(mtd, info);
458
459 return info->pair;
460}
461EXPORT_SYMBOL_GPL(mtd_pairing_info_to_wunit);
462
463/**
464 * mtd_pairing_groups - get the number of pairing groups
465 * @mtd: pointer to new MTD device info structure
466 *
467 * Returns the number of pairing groups.
468 *
469 * This number is usually equal to the number of bits exposed by a single
470 * cell, and can be used in conjunction with mtd_pairing_info_to_wunit()
471 * to iterate over all pages of a given pair.
472 */
473int mtd_pairing_groups(struct mtd_info *mtd)
474{
475 if (!mtd->pairing || !mtd->pairing->ngroups)
476 return 1;
477
478 return mtd->pairing->ngroups;
479}
480EXPORT_SYMBOL_GPL(mtd_pairing_groups);
481
482/**
379 * add_mtd_device - register an MTD device 483 * add_mtd_device - register an MTD device
380 * @mtd: pointer to new MTD device info structure 484 * @mtd: pointer to new MTD device info structure
381 * 485 *
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index ec852fa9200f..c1f34f04e338 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -409,6 +409,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
409 slave->mtd.oobsize = master->oobsize; 409 slave->mtd.oobsize = master->oobsize;
410 slave->mtd.oobavail = master->oobavail; 410 slave->mtd.oobavail = master->oobavail;
411 slave->mtd.subpage_sft = master->subpage_sft; 411 slave->mtd.subpage_sft = master->subpage_sft;
412 slave->mtd.pairing = master->pairing;
412 413
413 slave->mtd.name = name; 414 slave->mtd.name = name;
414 slave->mtd.owner = master->owner; 415 slave->mtd.owner = master->owner;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 29a170612203..13f8052b9ff9 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -127,6 +127,82 @@ struct mtd_ooblayout_ops {
127 struct mtd_oob_region *oobfree); 127 struct mtd_oob_region *oobfree);
128}; 128};
129 129
130/**
131 * struct mtd_pairing_info - page pairing information
132 *
133 * @pair: pair id
134 * @group: group id
135 *
136 * The term "pair" is used here, even though TLC NANDs might group pages by 3
137 * (3 bits in a single cell). A pair should regroup all pages that are sharing
138 * the same cell. Pairs are then indexed in ascending order.
139 *
140 * @group is defining the position of a page in a given pair. It can also be
141 * seen as the bit position in the cell: page attached to bit 0 belongs to
142 * group 0, page attached to bit 1 belongs to group 1, etc.
143 *
144 * Example:
145 * The H27UCG8T2BTR-BC datasheet describes the following pairing scheme:
146 *
147 * group-0 group-1
148 *
149 * pair-0 page-0 page-4
150 * pair-1 page-1 page-5
151 * pair-2 page-2 page-8
152 * ...
153 * pair-127 page-251 page-255
154 *
155 *
156 * Note that the "group" and "pair" terms were extracted from Samsung and
157 * Hynix datasheets, and might be referenced under other names in other
158 * datasheets (Micron is describing this concept as "shared pages").
159 */
160struct mtd_pairing_info {
161 int pair;
162 int group;
163};
164
165/**
166 * struct mtd_pairing_scheme - page pairing scheme description
167 *
168 * @ngroups: number of groups. Should be related to the number of bits
169 * per cell.
170 * @get_info: converts a write-unit (page number within an erase block) into
171 * mtd_pairing information (pair + group). This function should
172 * fill the info parameter based on the wunit index or return
173 * -EINVAL if the wunit parameter is invalid.
174 * @get_wunit: converts pairing information into a write-unit (page) number.
175 * This function should return the wunit index pointed by the
176 * pairing information described in the info argument. It should
177 * return -EINVAL, if there's no wunit corresponding to the
178 * passed pairing information.
179 *
180 * See mtd_pairing_info documentation for a detailed explanation of the
181 * pair and group concepts.
182 *
183 * The mtd_pairing_scheme structure provides a generic solution to represent
184 * NAND page pairing scheme. Instead of exposing two big tables to do the
185 * write-unit <-> (pair + group) conversions, we ask the MTD drivers to
186 * implement the ->get_info() and ->get_wunit() functions.
187 *
188 * MTD users will then be able to query these information by using the
189 * mtd_pairing_info_to_wunit() and mtd_wunit_to_pairing_info() helpers.
190 *
191 * @ngroups is here to help MTD users iterating over all the pages in a
192 * given pair. This value can be retrieved by MTD users using the
193 * mtd_pairing_groups() helper.
194 *
195 * Examples are given in the mtd_pairing_info_to_wunit() and
196 * mtd_wunit_to_pairing_info() documentation.
197 */
198struct mtd_pairing_scheme {
199 int ngroups;
200 int (*get_info)(struct mtd_info *mtd, int wunit,
201 struct mtd_pairing_info *info);
202 int (*get_wunit)(struct mtd_info *mtd,
203 const struct mtd_pairing_info *info);
204};
205
130struct module; /* only needed for owner field in mtd_info */ 206struct module; /* only needed for owner field in mtd_info */
131 207
132struct mtd_info { 208struct mtd_info {
@@ -188,6 +264,9 @@ struct mtd_info {
188 /* OOB layout description */ 264 /* OOB layout description */
189 const struct mtd_ooblayout_ops *ooblayout; 265 const struct mtd_ooblayout_ops *ooblayout;
190 266
267 /* NAND pairing scheme, only provided for MLC/TLC NANDs */
268 const struct mtd_pairing_scheme *pairing;
269
191 /* the ecc step size. */ 270 /* the ecc step size. */
192 unsigned int ecc_step_size; 271 unsigned int ecc_step_size;
193 272
@@ -296,6 +375,12 @@ static inline void mtd_set_ooblayout(struct mtd_info *mtd,
296 mtd->ooblayout = ooblayout; 375 mtd->ooblayout = ooblayout;
297} 376}
298 377
378static inline void mtd_set_pairing_scheme(struct mtd_info *mtd,
379 const struct mtd_pairing_scheme *pairing)
380{
381 mtd->pairing = pairing;
382}
383
299static inline void mtd_set_of_node(struct mtd_info *mtd, 384static inline void mtd_set_of_node(struct mtd_info *mtd,
300 struct device_node *np) 385 struct device_node *np)
301{ 386{
@@ -312,6 +397,11 @@ static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
312 return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; 397 return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
313} 398}
314 399
400int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
401 struct mtd_pairing_info *info);
402int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
403 const struct mtd_pairing_info *info);
404int mtd_pairing_groups(struct mtd_info *mtd);
315int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); 405int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
316int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, 406int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
317 void **virt, resource_size_t *phys); 407 void **virt, resource_size_t *phys);
@@ -397,6 +487,23 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd)
397 return do_div(sz, mtd->writesize); 487 return do_div(sz, mtd->writesize);
398} 488}
399 489
490static inline int mtd_wunit_per_eb(struct mtd_info *mtd)
491{
492 return mtd->erasesize / mtd->writesize;
493}
494
495static inline int mtd_offset_to_wunit(struct mtd_info *mtd, loff_t offs)
496{
497 return mtd_div_by_ws(mtd_mod_by_eb(offs, mtd), mtd);
498}
499
500static inline loff_t mtd_wunit_to_offset(struct mtd_info *mtd, loff_t base,
501 int wunit)
502{
503 return base + (wunit * mtd->writesize);
504}
505
506
400static inline int mtd_has_oob(const struct mtd_info *mtd) 507static inline int mtd_has_oob(const struct mtd_info *mtd)
401{ 508{
402 return mtd->_read_oob && mtd->_write_oob; 509 return mtd->_read_oob && mtd->_write_oob;