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 | |
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')
-rw-r--r-- | drivers/mtd/nand/docg4.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 44 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 87 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/sm_common.c | 9 |
5 files changed, 72 insertions, 75 deletions
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index dc86d4a3c3dd..548db2389fab 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c | |||
@@ -1093,7 +1093,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1093 | struct nand_chip *nand = mtd->priv; | 1093 | struct nand_chip *nand = mtd->priv; |
1094 | struct docg4_priv *doc = nand->priv; | 1094 | struct docg4_priv *doc = nand->priv; |
1095 | struct nand_bbt_descr *bbtd = nand->badblock_pattern; | 1095 | struct nand_bbt_descr *bbtd = nand->badblock_pattern; |
1096 | int block = (int)(ofs >> nand->bbt_erase_shift); | ||
1097 | int page = (int)(ofs >> nand->page_shift); | 1096 | int page = (int)(ofs >> nand->page_shift); |
1098 | uint32_t g4_addr = mtd_to_docg4_address(page, 0); | 1097 | uint32_t g4_addr = mtd_to_docg4_address(page, 0); |
1099 | 1098 | ||
@@ -1108,9 +1107,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1108 | if (buf == NULL) | 1107 | if (buf == NULL) |
1109 | return -ENOMEM; | 1108 | return -ENOMEM; |
1110 | 1109 | ||
1111 | /* update bbt in memory */ | ||
1112 | nand->bbt[block / 4] |= 0x01 << ((block & 0x03) * 2); | ||
1113 | |||
1114 | /* write bit-wise negation of pattern to oob buffer */ | 1110 | /* write bit-wise negation of pattern to oob buffer */ |
1115 | memset(nand->oob_poi, 0xff, mtd->oobsize); | 1111 | memset(nand->oob_poi, 0xff, mtd->oobsize); |
1116 | for (i = 0; i < bbtd->len; i++) | 1112 | for (i = 0; i < bbtd->len; i++) |
@@ -1120,8 +1116,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1120 | write_page_prologue(mtd, g4_addr); | 1116 | write_page_prologue(mtd, g4_addr); |
1121 | docg4_write_page(mtd, nand, buf, 1); | 1117 | docg4_write_page(mtd, nand, buf, 1); |
1122 | ret = pageprog(mtd); | 1118 | ret = pageprog(mtd); |
1123 | if (!ret) | ||
1124 | mtd->ecc_stats.badblocks++; | ||
1125 | 1119 | ||
1126 | kfree(buf); | 1120 | kfree(buf); |
1127 | 1121 | ||
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index ef0978e498d7..bcf9bc55bee2 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c | |||
@@ -1148,43 +1148,31 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1148 | { | 1148 | { |
1149 | struct nand_chip *chip = mtd->priv; | 1149 | struct nand_chip *chip = mtd->priv; |
1150 | struct gpmi_nand_data *this = chip->priv; | 1150 | struct gpmi_nand_data *this = chip->priv; |
1151 | int block, ret = 0; | 1151 | int ret = 0; |
1152 | uint8_t *block_mark; | 1152 | uint8_t *block_mark; |
1153 | int column, page, status, chipnr; | 1153 | int column, page, status, chipnr; |
1154 | 1154 | ||
1155 | /* Get block number */ | 1155 | chipnr = (int)(ofs >> chip->chip_shift); |
1156 | block = (int)(ofs >> chip->bbt_erase_shift); | 1156 | chip->select_chip(mtd, chipnr); |
1157 | if (chip->bbt) | ||
1158 | chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); | ||
1159 | 1157 | ||
1160 | /* Do we have a flash based bad block table ? */ | 1158 | column = this->swap_block_mark ? mtd->writesize : 0; |
1161 | if (chip->bbt_options & NAND_BBT_USE_FLASH) | ||
1162 | ret = nand_update_bbt(mtd, ofs); | ||
1163 | else { | ||
1164 | chipnr = (int)(ofs >> chip->chip_shift); | ||
1165 | chip->select_chip(mtd, chipnr); | ||
1166 | 1159 | ||
1167 | column = this->swap_block_mark ? mtd->writesize : 0; | 1160 | /* Write the block mark. */ |
1161 | block_mark = this->data_buffer_dma; | ||
1162 | block_mark[0] = 0; /* bad block marker */ | ||
1168 | 1163 | ||
1169 | /* Write the block mark. */ | 1164 | /* Shift to get page */ |
1170 | block_mark = this->data_buffer_dma; | 1165 | page = (int)(ofs >> chip->page_shift); |
1171 | block_mark[0] = 0; /* bad block marker */ | ||
1172 | 1166 | ||
1173 | /* Shift to get page */ | 1167 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); |
1174 | page = (int)(ofs >> chip->page_shift); | 1168 | chip->write_buf(mtd, block_mark, 1); |
1169 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | ||
1175 | 1170 | ||
1176 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); | 1171 | status = chip->waitfunc(mtd, chip); |
1177 | chip->write_buf(mtd, block_mark, 1); | 1172 | if (status & NAND_STATUS_FAIL) |
1178 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | 1173 | ret = -EIO; |
1179 | 1174 | ||
1180 | status = chip->waitfunc(mtd, chip); | 1175 | chip->select_chip(mtd, -1); |
1181 | if (status & NAND_STATUS_FAIL) | ||
1182 | ret = -EIO; | ||
1183 | |||
1184 | chip->select_chip(mtd, -1); | ||
1185 | } | ||
1186 | if (!ret) | ||
1187 | mtd->ecc_stats.badblocks++; | ||
1188 | 1176 | ||
1189 | return ret; | 1177 | return ret; |
1190 | } | 1178 | } |
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 | /** |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 3f18776592da..bac481a123dd 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -1392,4 +1392,3 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) | |||
1392 | 1392 | ||
1393 | EXPORT_SYMBOL(nand_scan_bbt); | 1393 | EXPORT_SYMBOL(nand_scan_bbt); |
1394 | EXPORT_SYMBOL(nand_default_bbt); | 1394 | EXPORT_SYMBOL(nand_default_bbt); |
1395 | EXPORT_SYMBOL_GPL(nand_update_bbt); | ||
diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index e8181edebddd..e06b5e5d3287 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c | |||
@@ -42,7 +42,7 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
42 | { | 42 | { |
43 | struct mtd_oob_ops ops; | 43 | struct mtd_oob_ops ops; |
44 | struct sm_oob oob; | 44 | struct sm_oob oob; |
45 | int ret, error = 0; | 45 | int ret; |
46 | 46 | ||
47 | memset(&oob, -1, SM_OOB_SIZE); | 47 | memset(&oob, -1, SM_OOB_SIZE); |
48 | oob.block_status = 0x0F; | 48 | oob.block_status = 0x0F; |
@@ -61,11 +61,10 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
61 | printk(KERN_NOTICE | 61 | printk(KERN_NOTICE |
62 | "sm_common: can't mark sector at %i as bad\n", | 62 | "sm_common: can't mark sector at %i as bad\n", |
63 | (int)ofs); | 63 | (int)ofs); |
64 | error = -EIO; | 64 | return -EIO; |
65 | } else | 65 | } |
66 | mtd->ecc_stats.badblocks++; | ||
67 | 66 | ||
68 | return error; | 67 | return 0; |
69 | } | 68 | } |
70 | 69 | ||
71 | static struct nand_flash_dev nand_smartmedia_flash_ids[] = { | 70 | static struct nand_flash_dev nand_smartmedia_flash_ids[] = { |