aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdpart.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/mtdpart.c')
-rw-r--r--drivers/mtd/mtdpart.c171
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
66static int part_point (struct mtd_info *mtd, loff_t from, size_t len, 71static 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
77static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) 83static 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 90static int part_read_oob(struct mtd_info *mtd, loff_t from,
85static 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
99static 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
111static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 111static 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
160static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, 155static 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
177static 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
191static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 170static 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
220static 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
233static 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
247static 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
259static int part_erase (struct mtd_info *mtd, struct erase_info *instr) 194static 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)
329static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) 264static 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 */