aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBrian Norris <computersforpeace@gmail.com>2013-07-30 20:52:58 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2013-08-30 11:47:52 -0400
commit5a0edb251ae91c6f9b1f28dc165becd955666118 (patch)
tree2411a390a1c5350baaf152e431e579a2487de57a /drivers
parent39dbb02998d859f0fa12c5b495fe90681ba45ce2 (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.c6
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c44
-rw-r--r--drivers/mtd/nand/nand_base.c87
-rw-r--r--drivers/mtd/nand/nand_bbt.c1
-rw-r--r--drivers/mtd/nand/sm_common.c9
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 */
335static 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*/
341static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) 386static 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 */
2684static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) 2702static 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
1393EXPORT_SYMBOL(nand_scan_bbt); 1393EXPORT_SYMBOL(nand_scan_bbt);
1394EXPORT_SYMBOL(nand_default_bbt); 1394EXPORT_SYMBOL(nand_default_bbt);
1395EXPORT_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
71static struct nand_flash_dev nand_smartmedia_flash_ids[] = { 70static struct nand_flash_dev nand_smartmedia_flash_ids[] = {