[PATCH 13/17] NAND: make ->check_bad more user friendly
From: Maxim Levitsky
Date: Tue Feb 09 2010 - 11:58:41 EST
Currently to implement a custom ->check_bad one need to call
nand_get_device, nand_release_device.
Also it not possible to use mtd->read_oob because they call
nand_get_device too.
Refactor the code, so check_bad now always has to do nand_get_device
Thus it can use plain mtd->read_oob
Signed-off-by: Maxim Levitsky <maximlevitsky@xxxxxxxxx>
---
drivers/mtd/nand/cafe_nand.c | 2 +-
drivers/mtd/nand/diskonchip.c | 2 +-
drivers/mtd/nand/nand_base.c | 74 ++++++++++++++++++++++++++---------------
include/linux/mtd/nand.h | 2 +-
4 files changed, 50 insertions(+), 30 deletions(-)
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index c828d9a..8211197 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -577,7 +577,7 @@ static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
{
return 0;
}
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index b126cf8..ea3a3c9 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -854,7 +854,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
}
}
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
{
/* This is our last resort if we couldn't find or create a BBT. Just
pretend all blocks are good. */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index c393df3..86fa40a 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -312,22 +312,18 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
*
* Check, if the block is bad.
*/
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
{
int page, chipnr, res = 0;
struct nand_chip *chip = mtd->priv;
u16 bad;
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+ chipnr = (int)(ofs >> chip->chip_shift);
+ nand_get_device(chip, mtd, FL_READING);
- if (getchip) {
- chipnr = (int)(ofs >> chip->chip_shift);
-
- nand_get_device(chip, mtd, FL_READING);
-
- /* Select the NAND device */
- chip->select_chip(mtd, chipnr);
- }
+ /* Select the NAND device */
+ chip->select_chip(mtd, chipnr);
if (chip->options & NAND_BUSWIDTH_16) {
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
@@ -343,9 +339,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
res = 1;
}
- if (getchip)
- nand_release_device(mtd);
-
+ nand_release_device(mtd);
return res;
}
@@ -410,19 +404,17 @@ static int nand_check_wp(struct mtd_info *mtd)
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
* @mtd: MTD device structure
* @ofs: offset from device start
- * @getchip: 0, if the chip is already selected
* @allowbbt: 1, if its allowed to access the bbt area
*
* Check, if the block is bad. Either by reading the bad block table or
* calling of the scan function.
*/
-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
- int allowbbt)
+static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
{
struct nand_chip *chip = mtd->priv;
if (!chip->bbt)
- return chip->block_bad(mtd, ofs, getchip);
+ return chip->block_bad(mtd, ofs);
/* Return info from the table */
return nand_isbad_bbt(mtd, ofs, allowbbt);
@@ -2277,6 +2269,40 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
return nand_erase_nand(mtd, instr, 0);
}
+/**
+ * nand_erase_nand - [Internal] check to see if range contains bad blocks
+ * @mtd: MTD device structure
+ * @offs: start offset
+ * @len: length of the range
+ * @allowbbt: allow access to bbt
+ *
+ * Sanity check before doing the erase
+ */
+static int nand_check_range(struct mtd_info *mtd, loff_t offs, loff_t len,
+ int allow_bbt)
+{
+ struct nand_chip *chip = mtd->priv;
+ int page = offs >> chip->page_shift;
+ int mask = (1 << chip->page_shift) - 1;
+
+ if (len & mask || offs & mask) {
+ DEBUG(MTD_DEBUG_LEVEL0, "%s Unaligned access\n", __func__);
+ return -EINVAL;
+ }
+
+ while (offs < len) {
+ if (nand_block_checkbad(mtd, offs, allow_bbt)) {
+ printk(KERN_WARNING "%s: attempt to erase a bad block "
+ "at page 0x%08x\n", __func__, page);
+ return -EIO;
+ }
+
+ offs += (1 < chip->page_shift);
+ page++;
+ }
+ return 0;
+}
+
#define BBT_PAGE_MASK 0xffffff3f
/**
* nand_erase_nand - [Internal] erase block(s)
@@ -2321,6 +2347,10 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
+ /* See if we were asked to erase bad blocks */
+ if (nand_check_range(mtd, instr->addr, instr->len, allowbbt))
+ return -EINVAL;
+
/* Grab the lock and see if the device is available */
nand_get_device(chip, mtd, FL_ERASING);
@@ -2357,16 +2387,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
instr->state = MTD_ERASING;
while (len) {
- /*
- * heck if we have a bad block, we do not erase bad blocks !
- */
- if (nand_block_checkbad(mtd, ((loff_t) page) <<
- chip->page_shift, 0, allowbbt)) {
- printk(KERN_WARNING "%s: attempt to erase a bad block "
- "at page 0x%08x\n", __func__, page);
- instr->state = MTD_ERASE_FAILED;
- goto erase_exit;
- }
/*
* Invalidate the page cache, if we erase the block which
@@ -2490,7 +2510,7 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
if (offs > mtd->size)
return -EINVAL;
- return nand_block_checkbad(mtd, offs, 1, 0);
+ return nand_block_checkbad(mtd, offs, 0);
}
/**
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index ccab9df..921f24b 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -364,7 +364,7 @@ struct nand_chip {
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*select_chip)(struct mtd_info *mtd, int chip);
- int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+ int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
void (*cmd_ctrl)(struct mtd_info *mtd, int dat,
unsigned int ctrl);
--
1.6.3.3
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/