mtd: nand: refactor chip->block_markbad interface
authorBrian Norris <computersforpeace@gmail.com>
Wed, 31 Jul 2013 00:52:58 +0000 (17:52 -0700)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Fri, 30 Aug 2013 15:47:52 +0000 (16:47 +0100)
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>
drivers/mtd/nand/docg4.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/sm_common.c

index dc86d4a3c3ddbbee5ef8e84486d31024cae28fba..548db2389fab8b63e41f2f61731606c32643084a 100644 (file)
@@ -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);
 
index ef0978e498d746d73827664e71a6882763c61ebb..bcf9bc55bee2b3a7b00107c2d0419495991eadb9 100644 (file)
@@ -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;
 }
index 158240d5649a7758e25336b8451649e3e8418b80..5a7467c33757f00a01b77f4aa739c35d4404ba9b 100644 (file)
@@ -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);
 }
 
 /**
index 3f18776592da457f541912ac80e09503c9489308..bac481a123dd83884d2ceaf7ea0ce1b0cb95e194 100644 (file)
@@ -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);
index e8181edebddd10923904c4db4be17adf79d29316..e06b5e5d3287dbaceaeed98941a77dcb595a5b4c 100644 (file)
@@ -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[] = {