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 <peterpand...@micron.com>
---
 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

Reply via email to