diff options
Diffstat (limited to 'drivers/mtd/mtdpart.c')
-rw-r--r-- | drivers/mtd/mtdpart.c | 171 |
1 files changed, 55 insertions, 116 deletions
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 99395911d26..77a7123a5c5 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -51,16 +51,21 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, | |||
51 | size_t *retlen, u_char *buf) | 51 | size_t *retlen, u_char *buf) |
52 | { | 52 | { |
53 | struct mtd_part *part = PART(mtd); | 53 | struct mtd_part *part = PART(mtd); |
54 | int res; | ||
55 | |||
54 | if (from >= mtd->size) | 56 | if (from >= mtd->size) |
55 | len = 0; | 57 | len = 0; |
56 | else if (from + len > mtd->size) | 58 | else if (from + len > mtd->size) |
57 | len = mtd->size - from; | 59 | len = mtd->size - from; |
58 | if (part->master->read_ecc == NULL) | 60 | res = part->master->read (part->master, from + part->offset, |
59 | return part->master->read (part->master, from + part->offset, | 61 | len, retlen, buf); |
60 | len, retlen, buf); | 62 | if (unlikely(res)) { |
61 | else | 63 | if (res == -EUCLEAN) |
62 | return part->master->read_ecc (part->master, from + part->offset, | 64 | mtd->ecc_stats.corrected++; |
63 | len, retlen, buf, NULL, &mtd->oobinfo); | 65 | if (res == -EBADMSG) |
66 | mtd->ecc_stats.failed++; | ||
67 | } | ||
68 | return res; | ||
64 | } | 69 | } |
65 | 70 | ||
66 | static int part_point (struct mtd_info *mtd, loff_t from, size_t len, | 71 | static int part_point (struct mtd_info *mtd, loff_t from, size_t len, |
@@ -74,6 +79,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len, | |||
74 | return part->master->point (part->master, from + part->offset, | 79 | return part->master->point (part->master, from + part->offset, |
75 | len, retlen, buf); | 80 | len, retlen, buf); |
76 | } | 81 | } |
82 | |||
77 | static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) | 83 | static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) |
78 | { | 84 | { |
79 | struct mtd_part *part = PART(mtd); | 85 | struct mtd_part *part = PART(mtd); |
@@ -81,31 +87,25 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_ | |||
81 | part->master->unpoint (part->master, addr, from + part->offset, len); | 87 | part->master->unpoint (part->master, addr, from + part->offset, len); |
82 | } | 88 | } |
83 | 89 | ||
84 | 90 | static int part_read_oob(struct mtd_info *mtd, loff_t from, | |
85 | static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | 91 | struct mtd_oob_ops *ops) |
86 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
87 | { | 92 | { |
88 | struct mtd_part *part = PART(mtd); | 93 | struct mtd_part *part = PART(mtd); |
89 | if (oobsel == NULL) | 94 | int res; |
90 | oobsel = &mtd->oobinfo; | ||
91 | if (from >= mtd->size) | ||
92 | len = 0; | ||
93 | else if (from + len > mtd->size) | ||
94 | len = mtd->size - from; | ||
95 | return part->master->read_ecc (part->master, from + part->offset, | ||
96 | len, retlen, buf, eccbuf, oobsel); | ||
97 | } | ||
98 | 95 | ||
99 | static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, | ||
100 | size_t *retlen, u_char *buf) | ||
101 | { | ||
102 | struct mtd_part *part = PART(mtd); | ||
103 | if (from >= mtd->size) | 96 | if (from >= mtd->size) |
104 | len = 0; | 97 | return -EINVAL; |
105 | else if (from + len > mtd->size) | 98 | if (from + ops->len > mtd->size) |
106 | len = mtd->size - from; | 99 | return -EINVAL; |
107 | return part->master->read_oob (part->master, from + part->offset, | 100 | res = part->master->read_oob(part->master, from + part->offset, ops); |
108 | len, retlen, buf); | 101 | |
102 | if (unlikely(res)) { | ||
103 | if (res == -EUCLEAN) | ||
104 | mtd->ecc_stats.corrected++; | ||
105 | if (res == -EBADMSG) | ||
106 | mtd->ecc_stats.failed++; | ||
107 | } | ||
108 | return res; | ||
109 | } | 109 | } |
110 | 110 | ||
111 | static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 111 | static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, |
@@ -148,44 +148,23 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len, | |||
148 | len = 0; | 148 | len = 0; |
149 | else if (to + len > mtd->size) | 149 | else if (to + len > mtd->size) |
150 | len = mtd->size - to; | 150 | len = mtd->size - to; |
151 | if (part->master->write_ecc == NULL) | 151 | return part->master->write (part->master, to + part->offset, |
152 | return part->master->write (part->master, to + part->offset, | 152 | len, retlen, buf); |
153 | len, retlen, buf); | ||
154 | else | ||
155 | return part->master->write_ecc (part->master, to + part->offset, | ||
156 | len, retlen, buf, NULL, &mtd->oobinfo); | ||
157 | |||
158 | } | 153 | } |
159 | 154 | ||
160 | static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | 155 | static int part_write_oob(struct mtd_info *mtd, loff_t to, |
161 | size_t *retlen, const u_char *buf, | 156 | struct mtd_oob_ops *ops) |
162 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
163 | { | 157 | { |
164 | struct mtd_part *part = PART(mtd); | 158 | struct mtd_part *part = PART(mtd); |
165 | if (!(mtd->flags & MTD_WRITEABLE)) | ||
166 | return -EROFS; | ||
167 | if (oobsel == NULL) | ||
168 | oobsel = &mtd->oobinfo; | ||
169 | if (to >= mtd->size) | ||
170 | len = 0; | ||
171 | else if (to + len > mtd->size) | ||
172 | len = mtd->size - to; | ||
173 | return part->master->write_ecc (part->master, to + part->offset, | ||
174 | len, retlen, buf, eccbuf, oobsel); | ||
175 | } | ||
176 | 159 | ||
177 | static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, | ||
178 | size_t *retlen, const u_char *buf) | ||
179 | { | ||
180 | struct mtd_part *part = PART(mtd); | ||
181 | if (!(mtd->flags & MTD_WRITEABLE)) | 160 | if (!(mtd->flags & MTD_WRITEABLE)) |
182 | return -EROFS; | 161 | return -EROFS; |
162 | |||
183 | if (to >= mtd->size) | 163 | if (to >= mtd->size) |
184 | len = 0; | 164 | return -EINVAL; |
185 | else if (to + len > mtd->size) | 165 | if (to + ops->len > mtd->size) |
186 | len = mtd->size - to; | 166 | return -EINVAL; |
187 | return part->master->write_oob (part->master, to + part->offset, | 167 | return part->master->write_oob(part->master, to + part->offset, ops); |
188 | len, retlen, buf); | ||
189 | } | 168 | } |
190 | 169 | ||
191 | static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 170 | static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, |
@@ -208,52 +187,8 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, | |||
208 | struct mtd_part *part = PART(mtd); | 187 | struct mtd_part *part = PART(mtd); |
209 | if (!(mtd->flags & MTD_WRITEABLE)) | 188 | if (!(mtd->flags & MTD_WRITEABLE)) |
210 | return -EROFS; | 189 | return -EROFS; |
211 | if (part->master->writev_ecc == NULL) | 190 | return part->master->writev (part->master, vecs, count, |
212 | return part->master->writev (part->master, vecs, count, | ||
213 | to + part->offset, retlen); | 191 | to + part->offset, retlen); |
214 | else | ||
215 | return part->master->writev_ecc (part->master, vecs, count, | ||
216 | to + part->offset, retlen, | ||
217 | NULL, &mtd->oobinfo); | ||
218 | } | ||
219 | |||
220 | static int part_readv (struct mtd_info *mtd, struct kvec *vecs, | ||
221 | unsigned long count, loff_t from, size_t *retlen) | ||
222 | { | ||
223 | struct mtd_part *part = PART(mtd); | ||
224 | if (part->master->readv_ecc == NULL) | ||
225 | return part->master->readv (part->master, vecs, count, | ||
226 | from + part->offset, retlen); | ||
227 | else | ||
228 | return part->master->readv_ecc (part->master, vecs, count, | ||
229 | from + part->offset, retlen, | ||
230 | NULL, &mtd->oobinfo); | ||
231 | } | ||
232 | |||
233 | static int part_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, | ||
234 | unsigned long count, loff_t to, size_t *retlen, | ||
235 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
236 | { | ||
237 | struct mtd_part *part = PART(mtd); | ||
238 | if (!(mtd->flags & MTD_WRITEABLE)) | ||
239 | return -EROFS; | ||
240 | if (oobsel == NULL) | ||
241 | oobsel = &mtd->oobinfo; | ||
242 | return part->master->writev_ecc (part->master, vecs, count, | ||
243 | to + part->offset, retlen, | ||
244 | eccbuf, oobsel); | ||
245 | } | ||
246 | |||
247 | static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs, | ||
248 | unsigned long count, loff_t from, size_t *retlen, | ||
249 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
250 | { | ||
251 | struct mtd_part *part = PART(mtd); | ||
252 | if (oobsel == NULL) | ||
253 | oobsel = &mtd->oobinfo; | ||
254 | return part->master->readv_ecc (part->master, vecs, count, | ||
255 | from + part->offset, retlen, | ||
256 | eccbuf, oobsel); | ||
257 | } | 192 | } |
258 | 193 | ||
259 | static int part_erase (struct mtd_info *mtd, struct erase_info *instr) | 194 | static int part_erase (struct mtd_info *mtd, struct erase_info *instr) |
@@ -329,12 +264,17 @@ static int part_block_isbad (struct mtd_info *mtd, loff_t ofs) | |||
329 | static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) | 264 | static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) |
330 | { | 265 | { |
331 | struct mtd_part *part = PART(mtd); | 266 | struct mtd_part *part = PART(mtd); |
267 | int res; | ||
268 | |||
332 | if (!(mtd->flags & MTD_WRITEABLE)) | 269 | if (!(mtd->flags & MTD_WRITEABLE)) |
333 | return -EROFS; | 270 | return -EROFS; |
334 | if (ofs >= mtd->size) | 271 | if (ofs >= mtd->size) |
335 | return -EINVAL; | 272 | return -EINVAL; |
336 | ofs += part->offset; | 273 | ofs += part->offset; |
337 | return part->master->block_markbad(part->master, ofs); | 274 | res = part->master->block_markbad(part->master, ofs); |
275 | if (!res) | ||
276 | mtd->ecc_stats.badblocks++; | ||
277 | return res; | ||
338 | } | 278 | } |
339 | 279 | ||
340 | /* | 280 | /* |
@@ -398,7 +338,7 @@ int add_mtd_partitions(struct mtd_info *master, | |||
398 | slave->mtd.type = master->type; | 338 | slave->mtd.type = master->type; |
399 | slave->mtd.flags = master->flags & ~parts[i].mask_flags; | 339 | slave->mtd.flags = master->flags & ~parts[i].mask_flags; |
400 | slave->mtd.size = parts[i].size; | 340 | slave->mtd.size = parts[i].size; |
401 | slave->mtd.oobblock = master->oobblock; | 341 | slave->mtd.writesize = master->writesize; |
402 | slave->mtd.oobsize = master->oobsize; | 342 | slave->mtd.oobsize = master->oobsize; |
403 | slave->mtd.ecctype = master->ecctype; | 343 | slave->mtd.ecctype = master->ecctype; |
404 | slave->mtd.eccsize = master->eccsize; | 344 | slave->mtd.eccsize = master->eccsize; |
@@ -415,10 +355,6 @@ int add_mtd_partitions(struct mtd_info *master, | |||
415 | slave->mtd.unpoint = part_unpoint; | 355 | slave->mtd.unpoint = part_unpoint; |
416 | } | 356 | } |
417 | 357 | ||
418 | if (master->read_ecc) | ||
419 | slave->mtd.read_ecc = part_read_ecc; | ||
420 | if (master->write_ecc) | ||
421 | slave->mtd.write_ecc = part_write_ecc; | ||
422 | if (master->read_oob) | 358 | if (master->read_oob) |
423 | slave->mtd.read_oob = part_read_oob; | 359 | slave->mtd.read_oob = part_read_oob; |
424 | if (master->write_oob) | 360 | if (master->write_oob) |
@@ -443,12 +379,6 @@ int add_mtd_partitions(struct mtd_info *master, | |||
443 | } | 379 | } |
444 | if (master->writev) | 380 | if (master->writev) |
445 | slave->mtd.writev = part_writev; | 381 | slave->mtd.writev = part_writev; |
446 | if (master->readv) | ||
447 | slave->mtd.readv = part_readv; | ||
448 | if (master->writev_ecc) | ||
449 | slave->mtd.writev_ecc = part_writev_ecc; | ||
450 | if (master->readv_ecc) | ||
451 | slave->mtd.readv_ecc = part_readv_ecc; | ||
452 | if (master->lock) | 382 | if (master->lock) |
453 | slave->mtd.lock = part_lock; | 383 | slave->mtd.lock = part_lock; |
454 | if (master->unlock) | 384 | if (master->unlock) |
@@ -528,8 +458,17 @@ int add_mtd_partitions(struct mtd_info *master, | |||
528 | parts[i].name); | 458 | parts[i].name); |
529 | } | 459 | } |
530 | 460 | ||
531 | /* copy oobinfo from master */ | 461 | slave->mtd.ecclayout = master->ecclayout; |
532 | memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo)); | 462 | if (master->block_isbad) { |
463 | uint32_t offs = 0; | ||
464 | |||
465 | while(offs < slave->mtd.size) { | ||
466 | if (master->block_isbad(master, | ||
467 | offs + slave->offset)) | ||
468 | slave->mtd.ecc_stats.badblocks++; | ||
469 | offs += slave->mtd.erasesize; | ||
470 | } | ||
471 | } | ||
533 | 472 | ||
534 | if(parts[i].mtdp) | 473 | if(parts[i].mtdp) |
535 | { /* store the object pointer (caller may or may not register it */ | 474 | { /* store the object pointer (caller may or may not register it */ |