aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2015-11-16 09:53:13 -0500
committerBoris Brezillon <boris.brezillon@free-electrons.com>2016-09-15 10:47:56 -0400
commit477b0229ac9bc275f6f8d2c27a2d08b246fccd0e (patch)
tree578e6574229ac57723e64545a824a0aa50127340 /include/linux
parent29b4817d4018df78086157ea3a55c1d9424a7cfc (diff)
mtd: introduce the mtd_pairing_scheme concept
MLC and TLC NAND devices are using NAND cells exposing more than one bit, but instead of attaching all the bits in a given cell to a single NAND page, each bit is usually attached to a different page. This concept is called 'page pairing', and has significant impacts on the flash storage usage. The main problem showed by these devices is that interrupting a page program operation may not only corrupt the page we are programming but also the page it is paired with, hence the need to expose to MTD users the pairing scheme information. The pairing APIs allows one to query pairing information attached to a given page (here called wunit), or the other way around (the wunit pointed by pairing information). It also provides several helpers to help the conversion between absolute offsets and wunits, and query the number of pairing groups. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Reviewed-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/mtd/mtd.h107
1 files changed, 107 insertions, 0 deletions
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;