diff options
author | Brian Norris <computersforpeace@gmail.com> | 2016-10-08 15:23:37 -0400 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2016-10-08 23:56:54 -0400 |
commit | 69db4aa44fdd8befc2eccd1313d841c5128c385c (patch) | |
tree | 1b84be76e9497231ed8027cf2a22b79fab64a87c | |
parent | f5b88de284932def6850e976c18d25940c1b2c3d (diff) | |
parent | 477b0229ac9bc275f6f8d2c27a2d08b246fccd0e (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.c | 104 | ||||
-rw-r--r-- | drivers/mtd/mtdpart.c | 1 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 107 |
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 | */ | ||
404 | int 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 | } | ||
420 | EXPORT_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 | */ | ||
446 | int 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 | } | ||
461 | EXPORT_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 | */ | ||
473 | int 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 | } | ||
480 | EXPORT_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 | */ | ||
160 | struct 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 | */ | ||
198 | struct 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 | |||
130 | struct module; /* only needed for owner field in mtd_info */ | 206 | struct module; /* only needed for owner field in mtd_info */ |
131 | 207 | ||
132 | struct mtd_info { | 208 | struct 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 | ||
378 | static inline void mtd_set_pairing_scheme(struct mtd_info *mtd, | ||
379 | const struct mtd_pairing_scheme *pairing) | ||
380 | { | ||
381 | mtd->pairing = pairing; | ||
382 | } | ||
383 | |||
299 | static inline void mtd_set_of_node(struct mtd_info *mtd, | 384 | static 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 | ||
400 | int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit, | ||
401 | struct mtd_pairing_info *info); | ||
402 | int mtd_pairing_info_to_wunit(struct mtd_info *mtd, | ||
403 | const struct mtd_pairing_info *info); | ||
404 | int mtd_pairing_groups(struct mtd_info *mtd); | ||
315 | int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); | 405 | int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); |
316 | int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, | 406 | int 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 | ||
490 | static inline int mtd_wunit_per_eb(struct mtd_info *mtd) | ||
491 | { | ||
492 | return mtd->erasesize / mtd->writesize; | ||
493 | } | ||
494 | |||
495 | static 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 | |||
500 | static 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 | |||
400 | static inline int mtd_has_oob(const struct mtd_info *mtd) | 507 | static 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; |