[RFC 2/2] mtd: nand: onenand: Switch OneNAND core to use the common BBM code
Kamil Debski
kamil.debski at imgtec.com
Wed Jun 17 09:40:35 PDT 2015
This patch switches the OneNAND core to use the common Bad Block
Management.
List of changes:
- move instance of struct nand_bbt_descr from onenand_bbt.c to
onenand_base.c
- move onenand_default_bbt, onenand_init_bbm, from onenand_bbt.c to
onenand_base.c
- change onenand_base.c to use struct mtd_info to access struct bbm_info
instead of struct onenand_chip
- remove functions from onenad_bbt.c that are already in nand_bbt.c:
check_short_pattern, create_bbt, onenand_memory_bbt, onenand_isbad_bbt,
Signed-off-by: Kamil Debski <kamil.debski at imgtec.com>
---
drivers/mtd/onenand/onenand_base.c | 71 +++++++++++--
drivers/mtd/onenand/onenand_bbt.c | 201 +-----------------------------------
include/linux/mtd/onenand.h | 2 -
3 files changed, 69 insertions(+), 205 deletions(-)
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 43b3392..5377e62 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1560,6 +1560,62 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
return 0;
}
+/*
+ * Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks.
+ */
+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+
+static struct nand_bbt_descr largepage_memorybased = {
+ .options = 0,
+ .offs = 0,
+ .len = 2,
+ .pattern = scan_ff_pattern,
+};
+
+/**
+ * onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device
+ * @param mtd MTD device structure
+ *
+ * This function selects the default bad block table
+ * support for the device and calls the onenand_scan_bbt function
+ */
+int onenand_default_bbt(struct mtd_info *mtd)
+{
+ struct bbm_info *bbm = mtd->bbm;
+
+ return onenand_scan_bbt(mtd, bbm->badblock_pattern);
+}
+EXPORT_SYMBOL(onenand_default_bbt);
+
+static int onenand_init_bbm(struct mtd_info *mtd, struct onenand_chip *this)
+{
+ struct bbm_info *bbm;
+
+ bbm = kzalloc(sizeof(*bbm) + this->writesize, GFP_KERNEL);
+ if (!bbm)
+ return -ENOMEM;
+
+ bbm->bbt_erase_shift = this->erase_shift;
+ bbm->badblockpos = ONENAND_BADBLOCK_POS;
+ /* The default behaviour of OneNAND BBM was equivalent
+ * to the behaviour of NAND BBM with the following
+ * option set. */
+ bbm->options = NAND_BBT_SCAN2NDPAGE;
+ /* bbm->badblock_pattern = this->badblock_pattern; */
+ /* bbm->badblock_pattern was always assigned &largepage_memorybase
+ * by the OneNAND BBM. */
+ bbm->badblock_pattern = &largepage_memorybased;
+ bbm->chipsize = this->chipsize;
+ bbm->numchips = 1;
+ bbm->page_shift = this->page_shift;
+ /* XXX should it be copied or allocated ? */
+ bbm->databuf = (uint8_t *)(bbm + 1);
+
+ mtd->bbm = bbm;
+ return 0;
+}
+
/**
* onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
* @param mtd MTD device structure
@@ -1568,7 +1624,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
*
* OneNAND read out-of-band data from the spare area for bbt scan
*/
-int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
+int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
@@ -2225,8 +2281,7 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
*/
static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
{
- struct onenand_chip *this = mtd->priv;
- struct bbm_info *bbm = this->bbm;
+ struct bbm_info *bbm = mtd->bbm;
/* Return info from the table */
return bbm->isbad_bbt(mtd, ofs, allowbbt);
@@ -2566,7 +2621,7 @@ static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
struct onenand_chip *this = mtd->priv;
- struct bbm_info *bbm = this->bbm;
+ struct bbm_info *bbm = mtd->bbm;
u_char buf[2] = {0, 0};
struct mtd_oob_ops ops = {
.mode = MTD_OPS_PLACE_OOB,
@@ -4043,6 +4098,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
break;
}
+ ret = onenand_init_bbm(mtd, this);
+
this->subpagesize = mtd->writesize >> mtd->subpage_sft;
/*
@@ -4116,10 +4173,10 @@ void onenand_release(struct mtd_info *mtd)
mtd_device_unregister(mtd);
/* Free bad block table memory, if allocated */
- if (this->bbm) {
- struct bbm_info *bbm = this->bbm;
+ if (mtd->bbm) {
+ struct bbm_info *bbm = mtd->bbm;
kfree(bbm->bbt);
- kfree(this->bbm);
+ kfree(bbm);
}
/* Buffers allocated by onenand_scan */
if (this->options & ONENAND_PAGEBUF_ALLOC) {
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index 08d0085..932e511 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -7,165 +7,15 @@
* Kyungmin Park <kyungmin.park at samsung.com>
*
* Derived from nand_bbt.c
- *
- * TODO:
- * Split BBT core and chip specific BBT.
*/
#include <linux/slab.h>
+#include <linux/mtd/bbm.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/onenand.h>
#include <linux/export.h>
/**
- * check_short_pattern - [GENERIC] check if a pattern is in the buffer
- * @param buf the buffer to search
- * @param len the length of buffer to search
- * @param paglen the pagelength
- * @param td search pattern descriptor
- *
- * Check for a pattern at the given place. Used to search bad block
- * tables and good / bad block identifiers. Same as check_pattern, but
- * no optional empty check and the pattern is expected to start
- * at offset 0.
- *
- */
-static int check_short_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
-{
- int i;
- uint8_t *p = buf;
-
- /* Compare the pattern */
- for (i = 0; i < td->len; i++) {
- if (p[i] != td->pattern[i])
- return -1;
- }
- return 0;
-}
-
-/**
- * create_bbt - [GENERIC] Create a bad block table by scanning the device
- * @param mtd MTD device structure
- * @param buf temporary buffer
- * @param bd descriptor for the good/bad block search pattern
- * @param 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 mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
-{
- struct onenand_chip *this = mtd->priv;
- struct bbm_info *bbm = this->bbm;
- int i, j, numblocks, len, scanlen;
- int startblock;
- loff_t from;
- size_t readlen, ooblen;
- struct mtd_oob_ops ops;
- int rgn;
-
- printk(KERN_INFO "Scanning device for bad blocks\n");
-
- len = 2;
-
- /* We need only read few bytes from the OOB area */
- scanlen = ooblen = 0;
- readlen = bd->len;
-
- /* chip == -1 case only */
- /* Note that numblocks is 2 * (real numblocks) here;
- * see i += 2 below as it makses shifting and masking less painful
- */
- numblocks = this->chipsize >> (bbm->bbt_erase_shift - 1);
- startblock = 0;
- from = 0;
-
- ops.mode = MTD_OPS_PLACE_OOB;
- ops.ooblen = readlen;
- ops.oobbuf = buf;
- ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
-
- for (i = startblock; i < numblocks; ) {
- int ret;
-
- for (j = 0; j < len; j++) {
- /* No need to read pages fully,
- * just read required OOB bytes */
- ret = onenand_bbt_read_oob(mtd,
- from + j * this->writesize + bd->offs, &ops);
-
- /* If it is a initial bad block, just ignore it */
- if (ret == ONENAND_BBT_READ_FATAL_ERROR)
- return -EIO;
-
- if (ret || check_short_pattern(&buf[j * scanlen],
- scanlen, this->writesize, bd)) {
- bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
- printk(KERN_INFO "OneNAND eraseblock %d is an "
- "initial bad block\n", i >> 1);
- mtd->ecc_stats.badblocks++;
- break;
- }
- }
- i += 2;
-
- if (FLEXONENAND(this)) {
- rgn = flexonenand_region(mtd, from);
- from += mtd->eraseregions[rgn].erasesize;
- } else
- from += (1 << bbm->bbt_erase_shift);
- }
-
- return 0;
-}
-
-
-/**
- * onenand_memory_bbt - [GENERIC] create a memory based bad block table
- * @param mtd MTD device structure
- * @param bd descriptor for the good/bad block search pattern
- *
- * The function creates a memory based bbt by scanning the device
- * for manufacturer / software marked good / bad blocks
- */
-static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
-{
- struct onenand_chip *this = mtd->priv;
-
- return create_bbt(mtd, this->page_buf, bd, -1);
-}
-
-/**
- * onenand_isbad_bbt - [OneNAND Interface] Check if a block is bad
- * @param mtd MTD device structure
- * @param offs offset in the device
- * @param allowbbt allow access to bad block table region
- */
-static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
-{
- struct onenand_chip *this = mtd->priv;
- struct bbm_info *bbm = this->bbm;
- int block;
- uint8_t res;
-
- /* Get block number * 2 */
- block = (int) (onenand_block(this, offs) << 1);
- res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03;
-
- pr_debug("onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n",
- (unsigned int) offs, block >> 1, res);
-
- switch ((int) res) {
- case 0x00: return 0;
- case 0x01: return 1;
- case 0x02: return allowbbt ? 0 : 1;
- }
-
- return 1;
-}
-
-/**
* onenand_scan_bbt - [OneNAND Interface] scan, find, read and maybe create bad block table(s)
* @param mtd MTD device structure
* @param bd descriptor for the good/bad block search pattern
@@ -182,7 +32,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct onenand_chip *this = mtd->priv;
- struct bbm_info *bbm = this->bbm;
+ struct bbm_info *bbm = mtd->bbm;
int len, ret = 0;
len = this->chipsize >> (this->erase_shift + 2);
@@ -194,14 +44,12 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
/* Set the bad block position */
bbm->badblockpos = ONENAND_BADBLOCK_POS;
- /* Set erase shift */
- bbm->bbt_erase_shift = this->erase_shift;
-
if (!bbm->isbad_bbt)
- bbm->isbad_bbt = onenand_isbad_bbt;
+ bbm->isbad_bbt = nand_isbad_bbt;
/* Scan the device to build a memory based bad block table */
- if ((ret = onenand_memory_bbt(mtd, bd))) {
+ ret = nand_memory_bbt(mtd, bd);
+ if (ret) {
printk(KERN_ERR "onenand_scan_bbt: Can't scan flash and build the RAM-based BBT\n");
kfree(bbm->bbt);
bbm->bbt = NULL;
@@ -210,43 +58,4 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
return ret;
}
-/*
- * Define some generic bad / good block scan pattern which are used
- * while scanning a device for factory marked good / bad blocks.
- */
-static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
-
-static struct nand_bbt_descr largepage_memorybased = {
- .options = 0,
- .offs = 0,
- .len = 2,
- .pattern = scan_ff_pattern,
-};
-
-/**
- * onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device
- * @param mtd MTD device structure
- *
- * This function selects the default bad block table
- * support for the device and calls the onenand_scan_bbt function
- */
-int onenand_default_bbt(struct mtd_info *mtd)
-{
- struct onenand_chip *this = mtd->priv;
- struct bbm_info *bbm;
-
- this->bbm = kzalloc(sizeof(struct bbm_info), GFP_KERNEL);
- if (!this->bbm)
- return -ENOMEM;
-
- bbm = this->bbm;
-
- /* 1KB page has same configuration as 2KB page */
- if (!bbm->badblock_pattern)
- bbm->badblock_pattern = &largepage_memorybased;
-
- return onenand_scan_bbt(mtd, bbm->badblock_pattern);
-}
-
EXPORT_SYMBOL(onenand_scan_bbt);
-EXPORT_SYMBOL(onenand_default_bbt);
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 4596503..0d624bd 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -136,8 +136,6 @@ struct onenand_chip {
int subpagesize;
struct nand_ecclayout *ecclayout;
- void *bbm;
-
void *priv;
/*
--
1.7.9.5
More information about the linux-mtd
mailing list