diff options
Diffstat (limited to 'drivers/mtd/nand/raw/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/raw/nand_base.c | 63 |
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; } |