[U-Boot-Users] NAND bad blocks scan unacceptable slow

Nikita V. Youshchenko yoush at cs.msu.su
Sun Mar 23 21:21:18 CET 2008


Hello.

I'm working on a board that has a 256-megabyte NAND chip connected to
cpu GPIO interface.
I wrote some code that provide hardware access methods for struct nand_chip,
and then u-boot recognized the NAND chip, and read/write/erase worked.

However, on-boot scan for bad blocks takes up to 20 seconds, which is
unacceptable slow. Linux kernel scans for bad blocks on the same board,
using almost same code to access hardware, almost immediately.

I was able to fix this using a patch included below.

However, this all looks ugly. Look in nand_read_raw() in
drivers/mtd/nand/nand_base.c:

int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen)
{
	...
	int pagesize = mtd->oobblock + mtd->oobsize;
	...
	len += ooblen;
	while (len) {
		...
		len -= pagesize;
	...
	}
}

So, if len is not mtd->oobblock or ooblen is not mtd->oobsize, the loop most
likely won't terminate.
And of course all usages of nand_read_raw use exactly these parameters.

How to deal with this?

Nikita

P.S. The patch I used against slow bad block scan:

commit 9f09001529526e07ebb6e65a33baa4995198851c
Author: Nikita Youshchenko <yoush at cs.msu.su>
Date:   Fri Mar 21 21:08:06 2008 +0000

    nand: when scanning for bad blocks, read only oob area of nand flash
    
    This patch adds one more parameter to nand_read_raw(), which, when non-zero,
    causes it to read oob area only.
    It also renames nand_read_raw() to nand_read_raw_ext(), and provides
    a wrapper nand_read_raw() that calls nand_read_raw_ext() with extra parameter
    set to zero.
    It also makes bad block scan routine to call nand_read_raw_ext(), if it is
    going to check oob area only.
    
    This makes scanning for bad blocks 100 times faster.
    
    Signed-off-by: Nikita Youshchenko <yoush at cs.msu.su>

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 151f535..ed93a20 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1468,7 +1468,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
  *
  * Read raw data including oob into buffer
  */
-int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen)
+int nand_read_raw_ext (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen, int oob_only)
 {
 	struct nand_chip *this = mtd->priv;
 	int page = (int) (from >> this->page_shift);
@@ -1477,6 +1477,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
 	int cnt = 0;
 	int pagesize = mtd->oobblock + mtd->oobsize;
 	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
+	int column;
 
 	/* Do not allow reads past end of device */
 	if ((from + len) > mtd->size) {
@@ -1493,11 +1494,19 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
 	len += ooblen;
 
 	while (len) {
+		if (oob_only)
+			column = mtd->oobblock;
+		else
+			column = 0;
+
 		if (sndcmd)
-			this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask);
+			this->cmdfunc (mtd, NAND_CMD_READ0, column, page & this->pagemask);
 		sndcmd = 0;
 
-		this->read_buf (mtd, &buf[cnt], pagesize);
+		if (oob_only)
+			this->read_buf (mtd, &buf[cnt + mtd->oobblock], ooblen);
+		else
+			this->read_buf (mtd, &buf[cnt], pagesize);
 
 		len -= pagesize;
 		cnt += pagesize;
@@ -1518,6 +1527,10 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
 	return 0;
 }
 
+int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen)
+{
+	return nand_read_raw_ext(mtd, buf, from, len, ooblen, 0);
+}
 
 /**
  * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 19a9bc2..fcac13f 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -292,7 +292,10 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 	}
 
 	for (i = startblock; i < numblocks;) {
-		nand_read_raw (mtd, buf, from, readlen, ooblen);
+		if (bd->options & NAND_BBT_SCANEMPTY)
+			nand_read_raw (mtd, buf, from, readlen, ooblen);
+		else
+			nand_read_raw_ext (mtd, buf, from, readlen, ooblen, 1);
 		for (j = 0; j < len; j++) {
 			if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
 				this->bbt[i >> 3] |= 0x03 << (i & 0x6);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 4cc4a7d..fe7fd9a 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -63,6 +63,7 @@ extern void nand_release (struct mtd_info *mtd);
 
 /* Read raw data from the device without ECC */
 extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen);
+extern int nand_read_raw_ext (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen, int oob_only);
 
 
 /* This constant declares the max. oobsize / page, which
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20080323/849562bd/attachment.pgp 


More information about the U-Boot mailing list