summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/raw/nand_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/raw/nand_base.c')
-rw-r--r--drivers/mtd/nand/raw/nand_base.c63
1 files changed, 43 insertions, 20 deletions
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 6e2d728d2fd9..2cf71060d6f8 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -283,6 +283,31 @@ static void nand_release_device(struct nand_chip *chip)
}
/**
+ * nand_bbm_get_next_page - Get the next page for bad block markers
+ * @chip: NAND chip object
+ * @page: First page to start checking for bad block marker usage
+ *
+ * Returns an integer that corresponds to the page offset within a block, for
+ * a page that is used to store bad block markers. If no more pages are
+ * available, -EINVAL is returned.
+ */
+int nand_bbm_get_next_page(struct nand_chip *chip, int page)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int last_page = ((mtd->erasesize - mtd->writesize) >>
+ chip->page_shift) & chip->pagemask;
+
+ if (page == 0 && chip->options & NAND_BBM_FIRSTPAGE)
+ return 0;
+ else if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE)
+ return 1;
+ else if (page <= last_page && chip->options & NAND_BBM_LASTPAGE)
+ return last_page;
+
+ return -EINVAL;
+}
+
+/**
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
* @chip: NAND chip object
* @ofs: offset from device start
@@ -291,19 +316,15 @@ static void nand_release_device(struct nand_chip *chip)
*/
static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
- int page, page_end, res;
+ int first_page, page_offset;
+ int res;
u8 bad;
- if (chip->options & NAND_BBM_LASTPAGE)
- ofs += mtd->erasesize - mtd->writesize;
+ first_page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+ page_offset = nand_bbm_get_next_page(chip, 0);
- page = (int)(ofs >> chip->page_shift) & chip->pagemask;
- page_end = page + (((chip->options & NAND_BBM_FIRSTPAGE) &&
- (chip->options & NAND_BBM_SECONDPAGE)) ? 2 : 1);
-
- for (; page < page_end; page++) {
- res = chip->ecc.read_oob(chip, page);
+ while (page_offset >= 0) {
+ res = chip->ecc.read_oob(chip, first_page + page_offset);
if (res < 0)
return res;
@@ -315,6 +336,8 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
res = hweight8(bad) < chip->badblockbits;
if (res)
return res;
+
+ page_offset = nand_bbm_get_next_page(chip, page_offset + 1);
}
return 0;
@@ -494,7 +517,7 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs)
struct mtd_info *mtd = nand_to_mtd(chip);
struct mtd_oob_ops ops;
uint8_t buf[2] = { 0, 0 };
- int ret = 0, res, i = 0;
+ int ret = 0, res, page_offset;
memset(&ops, 0, sizeof(ops));
ops.oobbuf = buf;
@@ -507,18 +530,18 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs)
}
ops.mode = MTD_OPS_PLACE_OOB;
- /* Write to first/last page(s) if necessary */
- if (chip->options & NAND_BBM_LASTPAGE)
- ofs += mtd->erasesize - mtd->writesize;
- do {
- res = nand_do_write_oob(chip, ofs, &ops);
+ page_offset = nand_bbm_get_next_page(chip, 0);
+
+ while (page_offset >= 0) {
+ res = nand_do_write_oob(chip,
+ ofs + (page_offset * mtd->writesize),
+ &ops);
+
if (!ret)
ret = res;
- i++;
- ofs += mtd->writesize;
- } while ((chip->options & NAND_BBM_FIRSTPAGE) &&
- (chip->options & NAND_BBM_SECONDPAGE) && i < 2);
+ page_offset = nand_bbm_get_next_page(chip, page_offset + 1);
+ }
return ret;
}