[PATCH 6/6] mtd: nand: make new BBT work

From: Peter Pan 潘栋 (peterpandong)
Date: Wed Apr 15 2015 - 22:19:59 EST


Continue with Brain Norris's work. Allocate and initialize struct
nand_bbt in nand_default_bbt()(nand_base.c). Remove .bbt from nand_chip.
Complete hook nand_is_bad_bbm(nand_bbt.is_bad_bbm). Allocate and initialize
badblock_pattern in nand_chip if badblock_pattern does not exist.
And clean some checkpatch warnings.

TBD: Allocate badblock_pattern is a temporary way to make new BBT work.
Remove .badblock_pattern from struct nand_chip and use .badblockpos,
.bbt_options and .options instead is the next thing to do.

Signed-off-by: Peter Pan <peterpandong@xxxxxxxxxx>
---
drivers/mtd/nand/diskonchip.c | 3 +-
drivers/mtd/nand/docg4.c | 5 ++-
drivers/mtd/nand/nand_base.c | 100 ++++++++++++++++++++++++++++++++++++++++++
drivers/mtd/nand/nand_bbt.c | 16 ++++---
include/linux/mtd/nand.h | 1 -
include/linux/mtd/nand_bbt.h | 8 +++-
6 files changed, 121 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index e580014..b980d77 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -1613,7 +1613,8 @@ static int __init doc_probe(unsigned long physadr)
else
numchips = doc2001_init(mtd);

- if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
+ if ((ret = nand_scan(mtd, numchips))
+ || (ret = doc->late_init(mtd))) {
/* DBB note: i believe nand_release is necessary here, as
buffers may have been allocated in nand_base. Check with
Thomas. FIX ME! */
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index 9b671b9..5ed7c7c 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -1037,7 +1037,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
* operation after device power-up. The above read ensures it never is.
* Ugly, I know.
*/
- if (nand->bbt == NULL) /* no memory-based bbt */
+ if (nand->nand_bbt == NULL) /* no memory-based bbt */
goto exit;

if (mtd->ecc_stats.failed > eccfailed_stats) {
@@ -1064,7 +1064,8 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
unsigned long bits = ~buf[i];
for_each_set_bit(bitnum, &bits, 8) {
int badblock = block + 7 - bitnum;
- nand_bbt_markbad(nand->nand_bbt, badblock << nand->bbt_erase_shift);
+ nand_bbt_markbad(nand->nand_bbt, badblock
+ << nand->bbt_erase_shift);
mtd->ecc_stats.badblocks++;
dev_notice(doc->dev, "factory-marked bad block: %d\n",
badblock);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ff9db05..dbd9955 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -98,9 +98,13 @@ static int nand_get_device(struct mtd_info *mtd, int new_state);
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops);

+static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops);
+
static int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt);

+static int nand_bbt_erase_block(struct mtd_info *mtd, loff_t addr);
/*
* For devices which display every fart in the system on a separate LED. Is
* compiled away when LED support is disabled.
@@ -531,13 +535,102 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
return nand_bbt_isreserved(bbt, ofs);
}

+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
+/**
+ * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
+ * @chip: NAND chip to create descriptor for
+ *
+ * This function allocates and initializes a nand_bbt_descr for BBM detection
+ * based on the properties of @this. The new descriptor is stored in
+ * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
+ * passed to this function.
+ */
+static int nand_create_badblock_pattern(struct nand_chip *chip)
+{
+ struct nand_bbt_descr *bd;
+
+ if (chip->badblock_pattern) {
+ pr_warn("Bad block pattern already allocated; not replacing\n");
+ return -EINVAL;
+ }
+ bd = kzalloc(sizeof(*bd), GFP_KERNEL);
+ if (!bd)
+ return -ENOMEM;
+ bd->options = chip->bbt_options & BADBLOCK_SCAN_MASK;
+ bd->offs = chip->badblockpos;
+ bd->len = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
+ bd->pattern = scan_ff_pattern;
+ bd->options |= NAND_BBT_DYNAMICSTRUCT;
+ chip->badblock_pattern = bd;
+
+ return 0;
+}
+
+static int nand_is_bad_bbm(struct mtd_info *mtd, loff_t addr)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mtd_oob_ops ops;
+ struct nand_bbt_descr *bd = chip->badblock_pattern;
+ int j, ret;
+ int numpages;
+
+ if (bd->options & NAND_BBT_SCAN2NDPAGE)
+ numpages = 2;
+ else
+ numpages = 1;
+
+ ops.ooblen = mtd->oobsize;
+ ops.oobbuf = chip->buffers->databuf;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+ ops.mode = MTD_OPS_PLACE_OOB;
+
+ for (j = 0; j < numpages; j++) {
+ /*
+ * Read the full oob until read_oob is fixed to handle single
+ * byte reads for 16 bit buswidth.
+ */
+ ret = nand_do_read_oob(mtd, addr, &ops);
+ /* Ignore ECC errors when checking for BBM */
+ if (ret && !mtd_is_bitflip_or_eccerr(ret))
+ return ret;
+
+ if (memcmp(chip->buffers->databuf + bd->offs,
+ bd->pattern, bd->len))
+ return 1;
+
+ addr += mtd->writesize;
+ }
+
+ return 0;
+}
+
static int nand_default_bbt(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
+ struct nand_bbt *bbt = kzalloc(sizeof(struct nand_bbt), GFP_KERNEL);
+
+ if (!bbt)
+ return -ENOMEM;
+
+ bbt->bbt_options = chip->bbt_options;
+ bbt->mtd = mtd;
+ bbt->numchips = chip->numchips;
+ bbt->chipsize = chip->chipsize;
+ bbt->chip_shift = chip->chip_shift;
+ bbt->bbt_erase_shift = chip->phys_erase_shift;
+ bbt->page_shift = chip->page_shift;
+ bbt->bbt_td = chip->bbt_td;
+ bbt->bbt_md = chip->bbt_md;
+ bbt->is_bad_bbm = nand_is_bad_bbm;
+ bbt->erase = nand_bbt_erase_block;
+ chip->nand_bbt = bbt;

return nand_bbt_init(chip->nand_bbt);
}

+
/**
* panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
* @mtd: MTD device structure
@@ -4208,6 +4301,8 @@ int nand_scan_tail(struct mtd_info *mtd)
if (chip->options & NAND_SKIP_BBTSCAN)
return 0;

+ if (!chip->badblock_pattern && nand_create_badblock_pattern(chip))
+ return -ENOMEM;
/* Build bad block table */
return chip->scan_bbt(mtd);
}
@@ -4271,6 +4366,11 @@ void nand_release(struct mtd_info *mtd)
kfree(chip->nand_bbt);
if (!(chip->options & NAND_OWN_BUFFERS))
kfree(chip->buffers);
+
+ /* Free bad block descriptor memory */
+ if (chip->badblock_pattern && chip->badblock_pattern->options
+ & NAND_BBT_DYNAMICSTRUCT)
+ kfree(chip->badblock_pattern);
}
EXPORT_SYMBOL_GPL(nand_release);

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 27269ea..ebbe6bf 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -245,7 +245,8 @@ static int read_bbt(struct nand_bbt *bbt, uint8_t *buf, int page, int num,
* Read the bad block table for all chips starting at a given page. We assume
* that the bbt bits are in consecutive order.
*/
-static int read_abs_bbt(struct nand_bbt *bbt, uint8_t *buf, struct nand_bbt_descr *td, int chip)
+static int read_abs_bbt(struct nand_bbt *bbt, uint8_t *buf,
+ struct nand_bbt_descr *td, int chip)
{
struct mtd_info *mtd = bbt->mtd;
int res = 0, i;
@@ -398,14 +399,13 @@ static void read_abs_bbts(struct nand_bbt *bbt, uint8_t *buf,
/**
* create_bbt - [GENERIC] Create a bad block table by scanning the device
* @bbt: NAND BBT structure
- * @buf: temporary buffer
* @chip: create the table for a specific chip, -1 read all chips; applies only
* if NAND_BBT_PERCHIP option is set
*
* Create a bad block table by scanning the device for the given good/bad block
* identify pattern.
*/
-static int create_bbt(struct nand_bbt *bbt, uint8_t *buf, int chip)
+static int create_bbt(struct nand_bbt *bbt, int chip)
{
struct mtd_info *mtd = bbt->mtd;
int i, startblock, numblocks;
@@ -463,7 +463,8 @@ static int create_bbt(struct nand_bbt *bbt, uint8_t *buf, int chip)
*
* The bbt ident pattern resides in the oob area of the first page in a block.
*/
-static int search_bbt(struct nand_bbt *bbt, uint8_t *buf, struct nand_bbt_descr *td)
+static int search_bbt(struct nand_bbt *bbt, uint8_t *buf,
+ struct nand_bbt_descr *td)
{
struct mtd_info *mtd = bbt->mtd;
int i, chips;
@@ -755,7 +756,7 @@ static int write_bbt(struct nand_bbt *bbt, uint8_t *buf,
*/
static inline int nand_memory_bbt(struct nand_bbt *bbt)
{
- return create_bbt(bbt, NULL /* FIXME: this->buffers->databuf */, -1);
+ return create_bbt(bbt, -1);
}

/**
@@ -827,7 +828,7 @@ static int check_create(struct nand_bbt *bbt, uint8_t *buf)

/* Create the table in memory by scanning the chip(s) */
if (!(bbt->bbt_options & NAND_BBT_CREATE_EMPTY))
- create_bbt(bbt, buf, chipsel);
+ create_bbt(bbt, chipsel);

td->version[i] = 1;
if (md)
@@ -912,7 +913,8 @@ static void mark_bbt_region(struct nand_bbt *bbt, struct nand_bbt_descr *td)
!(td->options & NAND_BBT_WRITE)) {
if (td->pages[i] == -1)
continue;
- block = td->pages[i] >> (bbt->bbt_erase_shift - bbt->page_shift);
+ block = td->pages[i] >>
+ (bbt->bbt_erase_shift - bbt->page_shift);
oldval = bbt_get_entry(bbt, block);
bbt_mark_entry(bbt, block, BBT_BLOCK_RESERVED);
if ((oldval != BBT_BLOCK_RESERVED) &&
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 539c9bf..fc53882 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -712,7 +712,6 @@ struct nand_chip {
struct nand_hw_control hwcontrol;

struct nand_bbt *nand_bbt;
- uint8_t *bbt;
struct nand_bbt_descr *bbt_td;
struct nand_bbt_descr *bbt_md;

diff --git a/include/linux/mtd/nand_bbt.h b/include/linux/mtd/nand_bbt.h
index f776695..ed71e0e 100644
--- a/include/linux/mtd/nand_bbt.h
+++ b/include/linux/mtd/nand_bbt.h
@@ -83,7 +83,7 @@ struct nand_bbt_descr {
* with NAND_BBT_CREATE.
*/
#define NAND_BBT_CREATE_EMPTY 0x00000400
-/* Write bbt if neccecary */
+/* Write bbt if necessary */
#define NAND_BBT_WRITE 0x00002000
/* Read and write back block contents when writing bbt */
#define NAND_BBT_SAVECONTENT 0x00004000
@@ -107,6 +107,12 @@ struct nand_bbt_descr {
*/
#define NAND_BBT_NO_OOB_BBM 0x00080000

+/*
+ * Flag to mark that the nand_bbt_descr was allocated dynamicaly and must
+ * be freed in nand_release().
+ */
+#define NAND_BBT_DYNAMICSTRUCT 0x80000000
+
/* The maximum number of blocks to scan for a bbt */
#define NAND_BBT_SCAN_MAXBLOCKS 4

--
1.9.1