summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorBrian Norris <computersforpeace@gmail.com>2013-07-30 17:52:58 -0700
committerDavid Woodhouse <David.Woodhouse@intel.com>2013-08-30 16:47:52 +0100
commit5a0edb251ae91c6f9b1f28dc165becd955666118 (patch)
tree2411a390a1c5350baaf152e431e579a2487de57a /drivers/mtd/nand
parent39dbb02998d859f0fa12c5b495fe90681ba45ce2 (diff)
downloadlinux-5a0edb251ae91c6f9b1f28dc165becd955666118.tar.bz2
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')
-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)
struct nand_chip *nand = mtd->priv;
struct docg4_priv *doc = nand->priv;
struct nand_bbt_descr *bbtd = nand->badblock_pattern;
- int block = (int)(ofs >> nand->bbt_erase_shift);
int page = (int)(ofs >> nand->page_shift);
uint32_t g4_addr = mtd_to_docg4_address(page, 0);
@@ -1108,9 +1107,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
if (buf == NULL)
return -ENOMEM;
- /* update bbt in memory */
- nand->bbt[block / 4] |= 0x01 << ((block & 0x03) * 2);
-
/* write bit-wise negation of pattern to oob buffer */
memset(nand->oob_poi, 0xff, mtd->oobsize);
for (i = 0; i < bbtd->len; i++)
@@ -1120,8 +1116,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
write_page_prologue(mtd, g4_addr);
docg4_write_page(mtd, nand, buf, 1);
ret = pageprog(mtd);
- if (!ret)
- mtd->ecc_stats.badblocks++;
kfree(buf);
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)
{
struct nand_chip *chip = mtd->priv;
struct gpmi_nand_data *this = chip->priv;
- int block, ret = 0;
+ int ret = 0;
uint8_t *block_mark;
int column, page, status, chipnr;
- /* Get block number */
- block = (int)(ofs >> chip->bbt_erase_shift);
- if (chip->bbt)
- chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+ chipnr = (int)(ofs >> chip->chip_shift);
+ chip->select_chip(mtd, chipnr);
- /* Do we have a flash based bad block table ? */
- if (chip->bbt_options & NAND_BBT_USE_FLASH)
- ret = nand_update_bbt(mtd, ofs);
- else {
- chipnr = (int)(ofs >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
+ column = this->swap_block_mark ? mtd->writesize : 0;
- column = this->swap_block_mark ? mtd->writesize : 0;
+ /* Write the block mark. */
+ block_mark = this->data_buffer_dma;
+ block_mark[0] = 0; /* bad block marker */
- /* Write the block mark. */
- block_mark = this->data_buffer_dma;
- block_mark[0] = 0; /* bad block marker */
+ /* Shift to get page */
+ page = (int)(ofs >> chip->page_shift);
- /* Shift to get page */
- page = (int)(ofs >> chip->page_shift);
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
+ chip->write_buf(mtd, block_mark, 1);
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
- chip->write_buf(mtd, block_mark, 1);
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
+ if (status & NAND_STATUS_FAIL)
+ ret = -EIO;
- status = chip->waitfunc(mtd, chip);
- if (status & NAND_STATUS_FAIL)
- ret = -EIO;
-
- chip->select_chip(mtd, -1);
- }
- if (!ret)
- mtd->ecc_stats.badblocks++;
+ chip->select_chip(mtd, -1);
return ret;
}
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)
}
/**
- * nand_default_block_markbad - [DEFAULT] mark a block bad
+ * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
* @mtd: MTD device structure
* @ofs: offset from device start
*
* This is the default implementation, which can be overridden by a hardware
- * specific driver. We try operations in the following order, according to our
- * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
+ * specific driver. It provides the details for writing a bad block marker to a
+ * block.
+ */
+static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mtd_oob_ops ops;
+ uint8_t buf[2] = { 0, 0 };
+ int ret = 0, res, i = 0;
+
+ ops.datbuf = NULL;
+ ops.oobbuf = buf;
+ ops.ooboffs = chip->badblockpos;
+ if (chip->options & NAND_BUSWIDTH_16) {
+ ops.ooboffs &= ~0x01;
+ ops.len = ops.ooblen = 2;
+ } else {
+ ops.len = ops.ooblen = 1;
+ }
+ ops.mode = MTD_OPS_PLACE_OOB;
+
+ /* Write to first/last page(s) if necessary */
+ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+ ofs += mtd->erasesize - mtd->writesize;
+ do {
+ res = nand_do_write_oob(mtd, ofs, &ops);
+ if (!ret)
+ ret = res;
+
+ i++;
+ ofs += mtd->writesize;
+ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+
+ return ret;
+}
+
+/**
+ * nand_block_markbad_lowlevel - mark a block bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * This function performs the generic NAND bad block marking steps (i.e., bad
+ * block table(s) and/or marker(s)). We only allow the hardware driver to
+ * specify how to write bad block markers to OOB (chip->block_markbad).
+ *
+ * We try operations in the following order, according to our bbt_options
+ * (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
* (1) erase the affected block, to allow OOB marker to be written cleanly
* (2) update in-memory BBT
* (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)
* Note that we retain the first error encountered in (3) or (4), finish the
* procedures, and dump the error in the end.
*/
-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
{
struct nand_chip *chip = mtd->priv;
- uint8_t buf[2] = { 0, 0 };
- int block, res, ret = 0, i = 0;
+ int block, res, ret = 0;
int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
if (write_oob) {
@@ -364,34 +408,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* Write bad block marker to OOB */
if (write_oob) {
- struct mtd_oob_ops ops;
- loff_t wr_ofs = ofs;
-
nand_get_device(mtd, FL_WRITING);
-
- ops.datbuf = NULL;
- ops.oobbuf = buf;
- ops.ooboffs = chip->badblockpos;
- if (chip->options & NAND_BUSWIDTH_16) {
- ops.ooboffs &= ~0x01;
- ops.len = ops.ooblen = 2;
- } else {
- ops.len = ops.ooblen = 1;
- }
- ops.mode = MTD_OPS_PLACE_OOB;
-
- /* Write to first/last page(s) if necessary */
- if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
- wr_ofs += mtd->erasesize - mtd->writesize;
- do {
- res = nand_do_write_oob(mtd, wr_ofs, &ops);
- if (!ret)
- ret = res;
-
- i++;
- wr_ofs += mtd->writesize;
- } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
-
+ ret = chip->block_markbad(mtd, ofs);
nand_release_device(mtd);
}
@@ -2683,7 +2701,6 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
*/
static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *chip = mtd->priv;
int ret;
ret = nand_block_isbad(mtd, ofs);
@@ -2694,7 +2711,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
return ret;
}
- return chip->block_markbad(mtd, ofs);
+ return nand_block_markbad_lowlevel(mtd, ofs);
}
/**
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)
EXPORT_SYMBOL(nand_scan_bbt);
EXPORT_SYMBOL(nand_default_bbt);
-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)
{
struct mtd_oob_ops ops;
struct sm_oob oob;
- int ret, error = 0;
+ int ret;
memset(&oob, -1, SM_OOB_SIZE);
oob.block_status = 0x0F;
@@ -61,11 +61,10 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
printk(KERN_NOTICE
"sm_common: can't mark sector at %i as bad\n",
(int)ofs);
- error = -EIO;
- } else
- mtd->ecc_stats.badblocks++;
+ return -EIO;
+ }
- return error;
+ return 0;
}
static struct nand_flash_dev nand_smartmedia_flash_ids[] = {