diff options
author | Brian Norris <computersforpeace@gmail.com> | 2013-07-30 20:52:58 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2013-08-30 11:47:52 -0400 |
commit | 5a0edb251ae91c6f9b1f28dc165becd955666118 (patch) | |
tree | 2411a390a1c5350baaf152e431e579a2487de57a /drivers/mtd/nand/nand_base.c | |
parent | 39dbb02998d859f0fa12c5b495fe90681ba45ce2 (diff) |
mtd: nand: refactor chip->block_markbad interface
The chip->block_markbad pointer should really only be responsible for
writing a bad block marker for new bad blocks. It should not take care
of BBT-related functionality, nor should it handle bookkeeping of bad
block stats.
This patch refactors the 3 users of the block_markbad interface (plus
the default nand_base implementation) so that the common code is kept in
nand_block_markbad_lowlevel(). It removes some inconsistencies between
the various implementations and should allow for more centralized
improvements in the future.
Because gpmi-nand no longer needs the nand_update_bbt() function, let's
stop exporting it as well.
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Acked-by: Huang Shijie <b32955@freescale.com> (for gpmi-nand parts)
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 87 |
1 files changed, 52 insertions, 35 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 158240d5649a..5a7467c33757 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -324,13 +324,58 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
324 | } | 324 | } |
325 | 325 | ||
326 | /** | 326 | /** |
327 | * nand_default_block_markbad - [DEFAULT] mark a block bad | 327 | * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker |
328 | * @mtd: MTD device structure | 328 | * @mtd: MTD device structure |
329 | * @ofs: offset from device start | 329 | * @ofs: offset from device start |
330 | * | 330 | * |
331 | * This is the default implementation, which can be overridden by a hardware | 331 | * This is the default implementation, which can be overridden by a hardware |
332 | * specific driver. We try operations in the following order, according to our | 332 | * specific driver. It provides the details for writing a bad block marker to a |
333 | * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH): | 333 | * block. |
334 | */ | ||
335 | static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||
336 | { | ||
337 | struct nand_chip *chip = mtd->priv; | ||
338 | struct mtd_oob_ops ops; | ||
339 | uint8_t buf[2] = { 0, 0 }; | ||
340 | int ret = 0, res, i = 0; | ||
341 | |||
342 | ops.datbuf = NULL; | ||
343 | ops.oobbuf = buf; | ||
344 | ops.ooboffs = chip->badblockpos; | ||
345 | if (chip->options & NAND_BUSWIDTH_16) { | ||
346 | ops.ooboffs &= ~0x01; | ||
347 | ops.len = ops.ooblen = 2; | ||
348 | } else { | ||
349 | ops.len = ops.ooblen = 1; | ||
350 | } | ||
351 | ops.mode = MTD_OPS_PLACE_OOB; | ||
352 | |||
353 | /* Write to first/last page(s) if necessary */ | ||
354 | if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) | ||
355 | ofs += mtd->erasesize - mtd->writesize; | ||
356 | do { | ||
357 | res = nand_do_write_oob(mtd, ofs, &ops); | ||
358 | if (!ret) | ||
359 | ret = res; | ||
360 | |||
361 | i++; | ||
362 | ofs += mtd->writesize; | ||
363 | } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); | ||
364 | |||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * nand_block_markbad_lowlevel - mark a block bad | ||
370 | * @mtd: MTD device structure | ||
371 | * @ofs: offset from device start | ||
372 | * | ||
373 | * This function performs the generic NAND bad block marking steps (i.e., bad | ||
374 | * block table(s) and/or marker(s)). We only allow the hardware driver to | ||
375 | * specify how to write bad block markers to OOB (chip->block_markbad). | ||
376 | * | ||
377 | * We try operations in the following order, according to our bbt_options | ||
378 | * (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH): | ||
334 | * (1) erase the affected block, to allow OOB marker to be written cleanly | 379 | * (1) erase the affected block, to allow OOB marker to be written cleanly |
335 | * (2) update in-memory BBT | 380 | * (2) update in-memory BBT |
336 | * (3) write bad block marker to OOB area of affected block | 381 | * (3) write bad block marker to OOB area of affected block |
@@ -338,11 +383,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
338 | * Note that we retain the first error encountered in (3) or (4), finish the | 383 | * Note that we retain the first error encountered in (3) or (4), finish the |
339 | * procedures, and dump the error in the end. | 384 | * procedures, and dump the error in the end. |
340 | */ | 385 | */ |
341 | static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | 386 | static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) |
342 | { | 387 | { |
343 | struct nand_chip *chip = mtd->priv; | 388 | struct nand_chip *chip = mtd->priv; |
344 | uint8_t buf[2] = { 0, 0 }; | 389 | int block, res, ret = 0; |
345 | int block, res, ret = 0, i = 0; | ||
346 | int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); | 390 | int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); |
347 | 391 | ||
348 | if (write_oob) { | 392 | if (write_oob) { |
@@ -364,34 +408,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
364 | 408 | ||
365 | /* Write bad block marker to OOB */ | 409 | /* Write bad block marker to OOB */ |
366 | if (write_oob) { | 410 | if (write_oob) { |
367 | struct mtd_oob_ops ops; | ||
368 | loff_t wr_ofs = ofs; | ||
369 | |||
370 | nand_get_device(mtd, FL_WRITING); | 411 | nand_get_device(mtd, FL_WRITING); |
371 | 412 | ret = chip->block_markbad(mtd, ofs); | |
372 | ops.datbuf = NULL; | ||
373 | ops.oobbuf = buf; | ||
374 | ops.ooboffs = chip->badblockpos; | ||
375 | if (chip->options & NAND_BUSWIDTH_16) { | ||
376 | ops.ooboffs &= ~0x01; | ||
377 | ops.len = ops.ooblen = 2; | ||
378 | } else { | ||
379 | ops.len = ops.ooblen = 1; | ||
380 | } | ||
381 | ops.mode = MTD_OPS_PLACE_OOB; | ||
382 | |||
383 | /* Write to first/last page(s) if necessary */ | ||
384 | if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) | ||
385 | wr_ofs += mtd->erasesize - mtd->writesize; | ||
386 | do { | ||
387 | res = nand_do_write_oob(mtd, wr_ofs, &ops); | ||
388 | if (!ret) | ||
389 | ret = res; | ||
390 | |||
391 | i++; | ||
392 | wr_ofs += mtd->writesize; | ||
393 | } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); | ||
394 | |||
395 | nand_release_device(mtd); | 413 | nand_release_device(mtd); |
396 | } | 414 | } |
397 | 415 | ||
@@ -2683,7 +2701,6 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) | |||
2683 | */ | 2701 | */ |
2684 | static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) | 2702 | static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) |
2685 | { | 2703 | { |
2686 | struct nand_chip *chip = mtd->priv; | ||
2687 | int ret; | 2704 | int ret; |
2688 | 2705 | ||
2689 | ret = nand_block_isbad(mtd, ofs); | 2706 | ret = nand_block_isbad(mtd, ofs); |
@@ -2694,7 +2711,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
2694 | return ret; | 2711 | return ret; |
2695 | } | 2712 | } |
2696 | 2713 | ||
2697 | return chip->block_markbad(mtd, ofs); | 2714 | return nand_block_markbad_lowlevel(mtd, ofs); |
2698 | } | 2715 | } |
2699 | 2716 | ||
2700 | /** | 2717 | /** |