aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nand_bbt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/nand_bbt.c')
-rw-r--r--drivers/mtd/nand/nand_bbt.c188
1 files changed, 139 insertions, 49 deletions
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 40f99304df76..480c3cbf9bf9 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -230,6 +230,42 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
230 return 0; 230 return 0;
231} 231}
232 232
233/*
234 * Scan read raw data from flash
235 */
236static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
237 size_t len)
238{
239 struct mtd_oob_ops ops;
240
241 ops.mode = MTD_OOB_RAW;
242 ops.ooboffs = 0;
243 ops.ooblen = mtd->oobsize;
244 ops.oobbuf = buf;
245 ops.datbuf = buf;
246 ops.len = len;
247
248 return mtd->read_oob(mtd, offs, &ops);
249}
250
251/*
252 * Scan write data with oob to flash
253 */
254static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
255 uint8_t *buf, uint8_t *oob)
256{
257 struct mtd_oob_ops ops;
258
259 ops.mode = MTD_OOB_PLACE;
260 ops.ooboffs = 0;
261 ops.ooblen = mtd->oobsize;
262 ops.datbuf = buf;
263 ops.oobbuf = oob;
264 ops.len = len;
265
266 return mtd->write_oob(mtd, offs, &ops);
267}
268
233/** 269/**
234 * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page 270 * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
235 * @mtd: MTD device structure 271 * @mtd: MTD device structure
@@ -241,27 +277,85 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
241 * We assume that the bbt bits are in consecutive order. 277 * We assume that the bbt bits are in consecutive order.
242 * 278 *
243*/ 279*/
244static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) 280static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
281 struct nand_bbt_descr *td, struct nand_bbt_descr *md)
245{ 282{
246 struct nand_chip *this = mtd->priv; 283 struct nand_chip *this = mtd->priv;
247 284
248 /* Read the primary version, if available */ 285 /* Read the primary version, if available */
249 if (td->options & NAND_BBT_VERSION) { 286 if (td->options & NAND_BBT_VERSION) {
250 nand_read_raw(mtd, buf, td->pages[0] << this->page_shift, mtd->writesize, mtd->oobsize); 287 scan_read_raw(mtd, buf, td->pages[0] << this->page_shift,
288 mtd->writesize);
251 td->version[0] = buf[mtd->writesize + td->veroffs]; 289 td->version[0] = buf[mtd->writesize + td->veroffs];
252 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); 290 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
291 td->pages[0], td->version[0]);
253 } 292 }
254 293
255 /* Read the mirror version, if available */ 294 /* Read the mirror version, if available */
256 if (md && (md->options & NAND_BBT_VERSION)) { 295 if (md && (md->options & NAND_BBT_VERSION)) {
257 nand_read_raw(mtd, buf, md->pages[0] << this->page_shift, mtd->writesize, mtd->oobsize); 296 scan_read_raw(mtd, buf, md->pages[0] << this->page_shift,
297 mtd->writesize);
258 md->version[0] = buf[mtd->writesize + md->veroffs]; 298 md->version[0] = buf[mtd->writesize + md->veroffs];
259 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); 299 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
300 md->pages[0], md->version[0]);
260 } 301 }
261
262 return 1; 302 return 1;
263} 303}
264 304
305/*
306 * Scan a given block full
307 */
308static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
309 loff_t offs, uint8_t *buf, size_t readlen,
310 int scanlen, int len)
311{
312 int ret, j;
313
314 ret = scan_read_raw(mtd, buf, offs, readlen);
315 if (ret)
316 return ret;
317
318 for (j = 0; j < len; j++, buf += scanlen) {
319 if (check_pattern(buf, scanlen, mtd->writesize, bd))
320 return 1;
321 }
322 return 0;
323}
324
325/*
326 * Scan a given block partially
327 */
328static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
329 loff_t offs, uint8_t *buf, int len)
330{
331 struct mtd_oob_ops ops;
332 int j, ret;
333
334 ops.len = mtd->oobsize;
335 ops.ooblen = mtd->oobsize;
336 ops.oobbuf = buf;
337 ops.ooboffs = 0;
338 ops.datbuf = NULL;
339 ops.mode = MTD_OOB_PLACE;
340
341 for (j = 0; j < len; j++) {
342 /*
343 * Read the full oob until read_oob is fixed to
344 * handle single byte reads for 16 bit
345 * buswidth
346 */
347 ret = mtd->read_oob(mtd, offs, &ops);
348 if (ret)
349 return ret;
350
351 if (check_short_pattern(buf, bd))
352 return 1;
353
354 offs += mtd->writesize;
355 }
356 return 0;
357}
358
265/** 359/**
266 * create_bbt - [GENERIC] Create a bad block table by scanning the device 360 * create_bbt - [GENERIC] Create a bad block table by scanning the device
267 * @mtd: MTD device structure 361 * @mtd: MTD device structure
@@ -273,13 +367,14 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
273 * Create a bad block table by scanning the device 367 * Create a bad block table by scanning the device
274 * for the given good/bad block identify pattern 368 * for the given good/bad block identify pattern
275 */ 369 */
276static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) 370static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
371 struct nand_bbt_descr *bd, int chip)
277{ 372{
278 struct nand_chip *this = mtd->priv; 373 struct nand_chip *this = mtd->priv;
279 int i, j, numblocks, len, scanlen; 374 int i, numblocks, len, scanlen;
280 int startblock; 375 int startblock;
281 loff_t from; 376 loff_t from;
282 size_t readlen, ooblen; 377 size_t readlen;
283 378
284 printk(KERN_INFO "Scanning device for bad blocks\n"); 379 printk(KERN_INFO "Scanning device for bad blocks\n");
285 380
@@ -294,18 +389,17 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
294 389
295 if (!(bd->options & NAND_BBT_SCANEMPTY)) { 390 if (!(bd->options & NAND_BBT_SCANEMPTY)) {
296 /* We need only read few bytes from the OOB area */ 391 /* We need only read few bytes from the OOB area */
297 scanlen = ooblen = 0; 392 scanlen = 0;
298 readlen = bd->len; 393 readlen = bd->len;
299 } else { 394 } else {
300 /* Full page content should be read */ 395 /* Full page content should be read */
301 scanlen = mtd->writesize + mtd->oobsize; 396 scanlen = mtd->writesize + mtd->oobsize;
302 readlen = len * mtd->writesize; 397 readlen = len * mtd->writesize;
303 ooblen = len * mtd->oobsize;
304 } 398 }
305 399
306 if (chip == -1) { 400 if (chip == -1) {
307 /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it 401 /* Note that numblocks is 2 * (real numblocks) here, see i+=2
308 * makes shifting and masking less painful */ 402 * below as it makes shifting and masking less painful */
309 numblocks = mtd->size >> (this->bbt_erase_shift - 1); 403 numblocks = mtd->size >> (this->bbt_erase_shift - 1);
310 startblock = 0; 404 startblock = 0;
311 from = 0; 405 from = 0;
@@ -324,35 +418,21 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
324 for (i = startblock; i < numblocks;) { 418 for (i = startblock; i < numblocks;) {
325 int ret; 419 int ret;
326 420
327 if (bd->options & NAND_BBT_SCANEMPTY) 421 if (bd->options & NAND_BBT_SCANALLPAGES)
328 if ((ret = nand_read_raw(mtd, buf, from, readlen, ooblen))) 422 ret = scan_block_full(mtd, bd, from, buf, readlen,
329 return ret; 423 scanlen, len);
330 424 else
331 for (j = 0; j < len; j++) { 425 ret = scan_block_fast(mtd, bd, from, buf, len);
332 if (!(bd->options & NAND_BBT_SCANEMPTY)) { 426
333 size_t retlen; 427 if (ret < 0)
334 428 return ret;
335 /* Read the full oob until read_oob is fixed to 429
336 * handle single byte reads for 16 bit buswidth */ 430 if (ret) {
337 ret = mtd->read_oob(mtd, from + j * mtd->writesize, mtd->oobsize, &retlen, buf); 431 this->bbt[i >> 3] |= 0x03 << (i & 0x6);
338 if (ret) 432 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
339 return ret; 433 i >> 1, (unsigned int)from);
340
341 if (check_short_pattern(buf, bd)) {
342 this->bbt[i >> 3] |= 0x03 << (i & 0x6);
343 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
344 i >> 1, (unsigned int)from);
345 break;
346 }
347 } else {
348 if (check_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
349 this->bbt[i >> 3] |= 0x03 << (i & 0x6);
350 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
351 i >> 1, (unsigned int)from);
352 break;
353 }
354 }
355 } 434 }
435
356 i += 2; 436 i += 2;
357 from += (1 << this->bbt_erase_shift); 437 from += (1 << this->bbt_erase_shift);
358 } 438 }
@@ -383,6 +463,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
383 int bits, startblock, block, dir; 463 int bits, startblock, block, dir;
384 int scanlen = mtd->writesize + mtd->oobsize; 464 int scanlen = mtd->writesize + mtd->oobsize;
385 int bbtblocks; 465 int bbtblocks;
466 int blocktopage = this->bbt_erase_shift - this->page_shift;
386 467
387 /* Search direction top -> down ? */ 468 /* Search direction top -> down ? */
388 if (td->options & NAND_BBT_LASTBLOCK) { 469 if (td->options & NAND_BBT_LASTBLOCK) {
@@ -412,11 +493,14 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
412 td->pages[i] = -1; 493 td->pages[i] = -1;
413 /* Scan the maximum number of blocks */ 494 /* Scan the maximum number of blocks */
414 for (block = 0; block < td->maxblocks; block++) { 495 for (block = 0; block < td->maxblocks; block++) {
496
415 int actblock = startblock + dir * block; 497 int actblock = startblock + dir * block;
498 loff_t offs = actblock << this->bbt_erase_shift;
499
416 /* Read first page */ 500 /* Read first page */
417 nand_read_raw(mtd, buf, actblock << this->bbt_erase_shift, mtd->writesize, mtd->oobsize); 501 scan_read_raw(mtd, buf, offs, mtd->writesize);
418 if (!check_pattern(buf, scanlen, mtd->writesize, td)) { 502 if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
419 td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); 503 td->pages[i] = actblock << blocktopage;
420 if (td->options & NAND_BBT_VERSION) { 504 if (td->options & NAND_BBT_VERSION) {
421 td->version[i] = buf[mtd->writesize + td->veroffs]; 505 td->version[i] = buf[mtd->writesize + td->veroffs];
422 } 506 }
@@ -481,8 +565,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
481 int nrchips, bbtoffs, pageoffs, ooboffs; 565 int nrchips, bbtoffs, pageoffs, ooboffs;
482 uint8_t msk[4]; 566 uint8_t msk[4];
483 uint8_t rcode = td->reserved_block_code; 567 uint8_t rcode = td->reserved_block_code;
484 size_t retlen, len = 0, ooblen; 568 size_t retlen, len = 0;
485 loff_t to; 569 loff_t to;
570 struct mtd_oob_ops ops;
571
572 ops.ooblen = mtd->oobsize;
573 ops.ooboffs = 0;
574 ops.datbuf = NULL;
575 ops.mode = MTD_OOB_PLACE;
486 576
487 if (!rcode) 577 if (!rcode)
488 rcode = 0xff; 578 rcode = 0xff;
@@ -583,10 +673,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
583 "bad block table\n"); 673 "bad block table\n");
584 } 674 }
585 /* Read oob data */ 675 /* Read oob data */
586 ooblen = (len >> this->page_shift) * mtd->oobsize; 676 ops.len = (len >> this->page_shift) * mtd->oobsize;
587 res = mtd->read_oob(mtd, to + mtd->writesize, ooblen, 677 ops.oobbuf = &buf[len];
588 &retlen, &buf[len]); 678 res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
589 if (res < 0 || retlen != ooblen) 679 if (res < 0 || ops.retlen != ops.len)
590 goto outerr; 680 goto outerr;
591 681
592 /* Calc the byte offset in the buffer */ 682 /* Calc the byte offset in the buffer */
@@ -635,7 +725,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
635 if (res < 0) 725 if (res < 0)
636 goto outerr; 726 goto outerr;
637 727
638 res = nand_write_raw(mtd, to, len, &retlen, buf, &buf[len]); 728 res = scan_write_bbt(mtd, to, len, buf, &buf[len]);
639 if (res < 0) 729 if (res < 0)
640 goto outerr; 730 goto outerr;
641 731