mtd/drivers/mtd/nand nand_base.c, 1.92, 1.93 nand_bbt.c, 1.9, 1.10 autcpu12.c, 1.16, 1.17

gleixner at infradead.org gleixner at infradead.org
Fri May 28 19:01:53 EDT 2004


Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv30633

Modified Files:
	nand_base.c nand_bbt.c autcpu12.c 
Log Message:
Make bad block table per chip default. Fake bad blocks in the bbt region. Signed-off-by: Thomas Gleixner <tglx at linutronix.de>

Index: nand_base.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand_base.c,v
retrieving revision 1.92
retrieving revision 1.93
diff -u -r1.92 -r1.93
--- nand_base.c	28 May 2004 18:20:50 -0000	1.92
+++ nand_base.c	28 May 2004 23:01:50 -0000	1.93
@@ -385,7 +385,7 @@
 
 	if (getchip) {
 		page = ((int) ofs) >> this->page_shift;
-		chipnr = (int)((unsigned long) ofs / this->chipsize);
+		chipnr = (int)(ofs >> this->chip_shift);
 
 		/* Grab the lock and see if the device is available */
 		nand_get_chip (this, mtd, FL_READING);
@@ -437,7 +437,7 @@
 
 	/* Do we have a flash based bad block table ? */
 	if (this->options & NAND_USE_FLASH_BBT)
-		return nand_update_bbt (mtd);
+		return nand_update_bbt (mtd, ofs);
 		
 	/* We write two bytes, so we dont have to mess with 16 bit access */
 	ofs += mtd->oobsize + (this->badblockpos & ~0x01);
@@ -464,22 +464,20 @@
  * @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)
+static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
 {
 	struct nand_chip *this = mtd->priv;
-	int block;
 	
 	if (!this->bbt)
 		return this->block_bad(mtd, ofs, getchip);
 	
 	/* Return info from the table */
-	/* Get block number */
-	block = (int) (ofs >> (this->erase_shift - 1));
-	return this->bbt[block >> 3] & (1 << (block & 0x06)) ? 1 : 0;
+	return nand_isbad_bbt (mtd, ofs, allowbbt);
 }
 
 /**
@@ -756,7 +754,7 @@
 				break;
 		}
 		if (this->read_byte(mtd) & NAND_STATUS_READY)
-				break;
+			break;
 						
 		spin_unlock_bh (&this->chip_lock);
 		yield ();
@@ -1032,7 +1030,7 @@
 	oob_config = oobsel->eccpos;
 
 	/* Select the NAND device */
-	chipnr = (int)((unsigned long)from / this->chipsize);
+	chipnr = (int)(from >> this->chip_shift);
 	this->select_chip(mtd, chipnr);
 
 	/* First we calculate the starting page */
@@ -1242,7 +1240,7 @@
 
 	/* Shift to get page */
 	page = ((int) from) >> this->page_shift;
-	chipnr = (int)((unsigned long)from / this->chipsize);
+	chipnr = (int)(from >> this->chip_shift);
 	
 	/* Mask to get column */
 	col = from & (mtd->oobsize - 1);
@@ -1328,8 +1326,7 @@
 {
 	struct nand_chip *this = mtd->priv;
 	int page = (int) (from >> this->page_shift);
-	int chipshift = ffs(this->chipsize) - 1;
-	int chip = (int) (from >> chipshift);
+	int chip = (int) (from >> this->chip_shift);
 	int sndcmd = 1;
 	int cnt = 0;
 	int pagesize = mtd->oobblock + mtd->oobsize;
@@ -1496,7 +1493,7 @@
 	nand_get_chip (this, mtd, FL_WRITING);
 
 	/* Calculate chipnr */
-	chipnr = (int)((unsigned long) to / this->chipsize);
+	chipnr = (int)(to>> this->chip_shift);
 	/* Select the NAND device */
 	this->select_chip(mtd, chipnr);
 
@@ -1622,8 +1619,8 @@
 	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
 
 	/* Shift to get page */
-	page = ((int) to) >> this->page_shift;
-	chipnr = (int)((unsigned long)to / this->chipsize);
+	page = (int) (to >> this->page_shift);
+	chipnr = (int) (to >> this->chip_shift);
 
 	/* Mask to get column */
 	column = to & (mtd->oobsize - 1);
@@ -1770,7 +1767,7 @@
 	nand_get_chip (this, mtd, FL_WRITING);
 
 	/* Get the current chip-nr */
-	chipnr = (int)((unsigned long) to / this->chipsize);
+	chipnr = (int) (to >> this->chip_shift);
 	/* Select the NAND device */
 	this->select_chip(mtd, chipnr);
 
@@ -1920,7 +1917,7 @@
 	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
 	this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
 }
- 
+
 /**
  * nand_erase - [MTD Interface] erase block(s)
  * @mtd:	MTD device structure
@@ -1930,6 +1927,19 @@
  */
 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
 {
+	return nand_erase_nand (mtd, instr, 0);
+}
+ 
+/**
+ * nand_erase_intern - [NAND Interface] erase block(s)
+ * @mtd:	MTD device structure
+ * @instr:	erase instruction
+ * @allowbbt:	allow erasing the bbt area
+ *
+ * Erase one ore more blocks
+ */
+int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
+{
 	int page, len, status, pages_per_block, ret, chipnr;
 	struct nand_chip *this = mtd->priv;
 
@@ -1959,7 +1969,7 @@
 
 	/* Shift to get first page */
 	page = (int) (instr->addr >> this->page_shift);
-	chipnr = (int)((unsigned long)instr->addr / this->chipsize);
+	chipnr = (int) (instr->addr >> this->chip_shift);
 
 	/* Calculate pages in each block */
 	pages_per_block = 1 << (this->erase_shift - this->page_shift);
@@ -1982,7 +1992,7 @@
 
 	while (len) {
 		/* Check if we have a bad block, we do not erase bad blocks ! */
-		if (nand_block_checkbad(mtd, (loff_t) page << this->page_shift, 0)) {
+		if (nand_block_checkbad(mtd, (loff_t) page << this->page_shift, 0, allowbbt)) {
 			printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
 			instr->state = MTD_ERASE_FAILED;
 			goto erase_exit;
@@ -1990,7 +2000,7 @@
 		
 		/* Invalidate the page cache, if we erase the block which contains 
 		   the current cached page */
-		if (page >= this->pagebuf && this->pagebuf < (page + pages_per_block))  
+		if (page >= this->pagebuf && this->pagebuf < (page + pages_per_block))
 			this->pagebuf = -1;
 
 		this->erase_cmd (mtd, page & this->pagemask);
@@ -2091,7 +2101,7 @@
 	if (ofs > mtd->size) 
 		return -EINVAL;
 	
-	return nand_block_checkbad (mtd, ofs, 1);
+	return nand_block_checkbad (mtd, ofs, 1, 0);
 }
 
 /**
@@ -2229,6 +2239,7 @@
 		/* Calculate the address shift from the page size */	
 		this->page_shift = ffs(mtd->oobblock) - 1;
 		this->erase_shift = ffs(mtd->erasesize) - 1;
+		this->chip_shift = ffs(this->chipsize) - 1;
 
 		/* Set the bad block position */
 		this->badblockpos = mtd->oobblock > 512 ? 

Index: nand_bbt.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand_bbt.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- nand_bbt.c	28 May 2004 10:59:38 -0000	1.9
+++ nand_bbt.c	28 May 2004 23:01:50 -0000	1.10
@@ -144,7 +144,9 @@
 				uint8_t tmp = (dat >> j) & msk;
 				if (tmp == msk)
 					continue;
-				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_bbt: Bad block at 0x%08x\n",
+				/* Leave it for now, if its matured we can move this
+				 * message to MTD_DEBUG_LEVEL0 */
+				printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
 					((offs << 2) + (act >> 1)) << this->erase_shift);
 				/* Factory marked bad or worn out ? */	
 				if (tmp == 0)
@@ -164,21 +166,24 @@
  * @mtd:	MTD device structure
  * @buf:	temporary buffer
  * @td:		descriptor for the bad block table 
+ * @chip:	read the table for a specific chip, -1 read all chips.
+ *		Applies only if NAND_BBT_PERCHIP option is set
  *
  * 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 mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
+static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
 {
 	struct nand_chip *this = mtd->priv;
-	int res, i;
+	int res = 0, i;
 	int bits;
 
 	bits = td->options & NAND_BBT_NRBITS_MSK;
 	if (td->options & NAND_BBT_PERCHIP) {
 		int offs = 0;
 		for (i = 0; i < this->numchips; i++) {
-			res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->erase_shift, bits, offs);
+			if (chip == -1 || chip == i)
+				res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->erase_shift, bits, offs);
 			if (res)
 				return res;
 			offs += this->chipsize >> (this->erase_shift + 2);
@@ -208,14 +213,14 @@
 	int res;
 
 	/* Read the primary table */	
-	res = read_abs_bbt (mtd, buf, td);
+	res = read_abs_bbt (mtd, buf, td, -1);
 	if (res < 0)
 		return res;
 
 	if (!md)
 		return 0;	
 	/* Read the mirrored table */	
-	return  read_abs_bbt (mtd, buf, md);
+	return  read_abs_bbt (mtd, buf, md, -1);
 }
 
 /**
@@ -223,15 +228,18 @@
  * @mtd:	MTD device structure
  * @buf:	temporary buffer
  * @bd:		descriptor for the good/bad block search pattern
+ * @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 void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
+static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
 {
 	struct nand_chip *this = mtd->priv;
 	int i, j, numblocks, len, scanlen;
-	loff_t from = 0;
+	int startblock;
+	loff_t from;
 	size_t readlen, ooblen;
 
 	printk (KERN_INFO "Scanning device for bad blocks\n");
@@ -244,13 +252,28 @@
 	readlen = len * mtd->oobblock;
 	ooblen = len * mtd->oobsize;
 
-	/* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
-	 * makes shifting and masking less painful */
-	numblocks = mtd->size >> (this->erase_shift - 1);
-	for (i = 0; i < numblocks;) {
+	if (chip == -1) {
+		/* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
+		 * makes shifting and masking less painful */
+		numblocks = mtd->size >> (this->erase_shift - 1);
+		startblock = 0;
+		from = 0;
+	} else {
+		if (chip >= this->numchips) {
+			printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
+				chip + 1, this->numchips);
+			return;	
+		}
+		numblocks = this->chipsize >> (this->erase_shift - 1);
+		startblock = chip * numblocks;
+		numblocks += startblock;
+		from = startblock << (this->erase_shift - 1);
+	}
+	
+	for (i = startblock; i < numblocks;) {
 		nand_read_raw (mtd, buf, from, readlen, ooblen);
 		for (j = 0; j < len; j++) {
-			if (check_pattern (buf, scanlen, mtd->oobblock, bd)) {
+			if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
 				this->bbt[i >> 3] |= 0x03 << (i & 0x6);
 				printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 
 					i >> 1, (unsigned int) from);
@@ -309,9 +332,9 @@
 	/* Number of bits for each erase block in the bbt */
 	bits = td->options & NAND_BBT_NRBITS_MSK;
 	
-	/* Reset version information */
-	td->version = 0;	
 	for (i = 0; i < chips; i++) {
+		/* Reset version information */
+		td->version[i] = 0;	
 		td->pages[i] = -1;
 		/* Scan the maximum number of blocks */
 		for (block = 0; block < td->maxblocks; block++) {
@@ -322,7 +345,7 @@
 				td->pages[i] = actblock << (this->erase_shift - this->page_shift);
 				if (td->options & NAND_BBT_VERSION) {
 					int *p = (int *) &buf[mtd->oobblock + td->veroffs];
-					td->version = (int) le32_to_cpu (*p);
+					td->version[i] = (int) le32_to_cpu (*p);
 				}
 				break;
 			}
@@ -331,13 +354,12 @@
 	}
 	/* Check, if we found a bbt for each requested chip */
 	for (i = 0; i < chips; i++) {
-		printk (KERN_DEBUG "Bad block table found at page %d, version %d\n", td->pages[i], td->version);
-		if (td->pages[i] == -1) {
+		if (td->pages[i] == -1)
 			printk (KERN_WARNING "Bad block table not found for chip %d\n", i);
-			return -1;
-		}
+		else
+			printk (KERN_DEBUG "Bad block table found at page %d, version %d\n", td->pages[i], td->version[i]);
 	}
-	return 0;
+	return 0;	
 }
 
 /**
@@ -352,52 +374,17 @@
 static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, 
 	struct nand_bbt_descr *td, struct nand_bbt_descr *md)
 {
-	int res = 0;
-
 	/* Search the primary table */
-	if (search_bbt (mtd, buf, td))
-		res |= 1;
+	search_bbt (mtd, buf, td);
 		
 	/* Search the mirror table */
-	if (!md || search_bbt (mtd, buf, md)) 
-		res |= 2;
-	
-//	td->version++;
+	if (md)
+		search_bbt (mtd, buf, md);
 	
-	/* Check result */
-	switch (res) {
-	/* Both tables found */
-	case 0:
-		/* Compare versions, if they dont match mark the
-		 * older table for rewrite
-		 */
-		if (td->version >= md->version) {
-			read_abs_bbt (mtd, buf, td);
-			res = td->version == md->version ? 0 : 2;
-			md->version = td->version;
-		} else {
-			read_abs_bbt (mtd, buf, md);
-			res = 1;
-			td->version = md->version;
-		}
-		break;
-
-	/* Table 1 found */
-	case 2:			
-		read_abs_bbt (mtd, buf, td);
-		break;
-
-	/* Table 2 found */
-	case 1:
-		read_abs_bbt (mtd, buf, md);
-		break;
-
-	default:
-		break;	
-	}	
-	return res;	
+	/* Force result check */
+	return 1;	
 }
-
+	
 
 /** 
  * write_bbt - [GENERIC] (Re)write the bad block table
@@ -406,31 +393,41 @@
  * @buf:	temporary buffer
  * @td:		descriptor for the bad block table 
  * @md:		descriptor for the bad block table mirror
+ * @chipsel:	selector for a specific chip, -1 for all
  *
  * (Re)write the bad block table
  *
 */
 static int write_bbt (struct mtd_info *mtd, uint8_t *buf, 
-	struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+	struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
 {
 	struct nand_chip *this = mtd->priv;
 	struct nand_oobinfo oobinfo;
 	struct erase_info einfo;
-	int i, j, res;
+	int i, j, res, chip;
 	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
-	int chip, nrchips, bbtoffs;
+	int nrchips, bbtoffs;
 	uint8_t msk[4];
 	size_t retlen, len = 0;
 	loff_t to;
 	
+	
 	/* Write bad block table per chip rather than per device ? */
 	if (td->options & NAND_BBT_PERCHIP)  
 		nrchips = this->numchips;
 	else
 		nrchips = 1;	
-
+	
+	/* Full device write or specific chip ? */	
+	if (chipsel == -1) 
+		chip = 0;
+	else {
+		nrchips = chipsel + 1;
+		chip = chipsel;
+	}
+	
 	/* Loop through the chips */
-	for (chip = 0; chip < nrchips; chip++) {
+	for (; chip < nrchips; chip++) {
 		
 		/* There was already a version of the table, reuse the page 
 		 * This applies for absolute placement too, as we have the 
@@ -469,18 +466,23 @@
 		/* Set up shift count and masks for the flash table */
 		bits = td->options & NAND_BBT_NRBITS_MSK;
 		switch (bits) {
-		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = 0x01; msk[3] = 0x01; break;
-		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = 0x01; msk[3] = 0x03; break;
-		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0c; msk[2] = 0x0c; msk[3] = 0x0f; break;
-		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0xf0; msk[2] = 0xf0; msk[3] = 0xff; break;
+		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = 0x00; msk[3] = 0x01; break;
+		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = 0x00; msk[3] = 0x03; break;
+		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = 0x00; msk[3] = 0x0f; break;
+		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = 0x00; msk[3] = 0xff; break;
 		default: return -EINVAL;
 		}
-	
-		numblocks = mtd->size >> this->erase_shift;
-		numblocks /= nrchips;
-		bbtoffs = (numblocks >> 2) * chip;
+		
+		if (chip != -1) {
+			numblocks = mtd->size >> this->erase_shift;
+			bbtoffs = 0;
+		} else {	
+			numblocks = this->chipsize >> this->erase_shift;
+			bbtoffs = (numblocks >> 2) * chip;
+		}	
+		
 		to = ((loff_t) page) << this->page_shift;
-
+		
 		/* Must we save the block contents ? */
 		if (td->options & NAND_BBT_SAVECONTENT) {
 			/* Make it block aligned */
@@ -519,7 +521,7 @@
 			memcpy (&buf[len + td->offs], td->pattern, td->len);
 			if (td->options & NAND_BBT_VERSION) {
 				int *p = (int *) &buf[len + td->veroffs];
-				*p = (int) cpu_to_le32 (td->version);
+				*p = (int) cpu_to_le32 (td->version[chip]);
 			}
 		}
 	
@@ -529,6 +531,7 @@
 			dat = this->bbt[bbtoffs + (i >> 2)];
 			for (j = 0; j < 4; j++ , i++) {
 				int sftcnt = (i << (3 - sft)) & sftmsk;
+				/* Do not store the reserved bbt blocks ! */
 				buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
 				dat >>= 2;
 			}
@@ -536,9 +539,9 @@
 		
 		memset (&einfo, 0, sizeof (einfo));
 		einfo.mtd = mtd;
-		einfo.addr = to;
+		einfo.addr = (unsigned long) to;
 		einfo.len = 1 << this->erase_shift;
-		res = mtd->erase (mtd, &einfo);
+		res = nand_erase_nand (mtd, &einfo, 1);
 		if (res < 0) {
 			printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
 			return res;
@@ -553,7 +556,7 @@
 			return res;
 		}
 		printk (KERN_DEBUG "Bad block table written to 0x%08x, version %d\n", 
-			(unsigned int) to, td->version);
+			(unsigned int) to, td->version[chip]);
 	
 		/* Mark it as used */
 		td->pages[chip] = page;
@@ -568,9 +571,6 @@
  *
  * The function creates a memory based bbt by scanning the device 
  * for manufacturer / software marked good / bad blocks
- *
- * The bad block table memory is allocated here. It must be freed
- * by calling the nand_free_bbt function.
 */
 static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
 {
@@ -578,10 +578,159 @@
 
 	/* Ensure that we only scan for the pattern and nothing else */
 	bd->options = 0;
-	create_bbt (mtd, this->data_buf, bd);
+	create_bbt (mtd, this->data_buf, bd, -1);
 	return 0;
 }
 
+/**
+ * check_create - [GENERIC] create and write bbt(s) if neccecary
+ * @mtd:	MTD device structure
+ * @buf:	temporary buffer
+ * @bd:		descriptor for the good/bad block search pattern
+ *
+ * The function checks the results of the previous call to read_bbt
+ * and creates / updates the bbt(s) if neccecary
+ * Creation is neccecary if no bbt was found for the chip/device
+ * Update is neccecary if one of the tables is missing or the
+ * version nr. of one table is less than the other
+*/
+static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
+{
+	int i, chips, writeops, chipsel, res;
+	struct nand_chip *this = mtd->priv;
+	struct nand_bbt_descr *td = this->bbt_td;
+	struct nand_bbt_descr *md = this->bbt_md;
+	struct nand_bbt_descr *rd;
+
+	/* Do we have a bbt per chip ? */
+	if (td->options & NAND_BBT_PERCHIP) 
+		chips = this->numchips;
+	else 
+		chips = 1;
+	
+	for (i = 0; i < chips; i++) {
+		writeops = 0;
+		rd = NULL;
+		/* Per chip or per device ? */
+		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
+		/* Mirrored table avilable ? */
+		if (md) {
+			if (td->pages[i] == -1 && md->pages[i] == -1) {
+				writeops = 0x03;
+				goto create;
+			}
+
+			if (td->pages[i] == -1) {
+				rd = md;				
+				writeops = 1;
+				goto writecheck;
+			}
+
+			if (md->pages[i] == -1) {
+				rd = td;
+				writeops = 2;
+				goto writecheck;
+			}
+
+			if (td->version[i] == md->version[i]) {
+				rd = td;
+				goto writecheck;
+			}	
+
+			if (td->version[i] > md->version[i]) {
+				rd = td;
+				md->version[i] = td->version[i];
+				writeops = 2;
+			} else {
+				rd = md;
+				td->version[i] = md->version[i];
+				writeops = 1;
+			}
+
+			goto writecheck;
+
+		} else {
+			if (td->pages[i] == -1) {
+				writeops = 0x01;
+				goto create;
+			}
+			rd = td;
+			goto writecheck;
+		}
+create:
+		/* Create the bad block table by scanning the device ? */
+		if (!(td->options & NAND_BBT_CREATE))
+			continue;	
+		
+		/* Create the table in memory by scanning the chip(s) */
+		create_bbt (mtd, buf, bd, chipsel);
+		
+		td->version[i] = 1;
+		if (md)
+			md->version[i] = 1;	
+writecheck:	
+		/* read back first ? */
+		if (rd)
+			read_abs_bbt (mtd, buf, rd, chipsel);
+
+		/* Write the bad block table to the device ? */
+		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
+			res = write_bbt (mtd, buf, td, md, chipsel);
+			if (res < 0)
+				return res;
+		}
+		
+		/* Write the mirror bad block table to the device ? */
+		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
+			res = write_bbt (mtd, buf, md, td, chipsel);
+			if (res < 0)
+				return res;
+		}
+	}
+	return 0;	
+}
+
+/**
+ * mark_bbt_regions - [GENERIC] mark the bad block table regions 
+ * @mtd:	MTD device structure
+ * @td:		bad block table descriptor
+ *
+ * The bad block table regions are marked as "bad" to prevent
+ * accidental erasures / writes. The regions are identified by
+ * the mark 0x02.
+*/
+static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
+{
+	struct nand_chip *this = mtd->priv;
+	int i, j, chips, block, nrblocks;
+
+	/* Do we have a bbt per chip ? */
+	if (td->options & NAND_BBT_PERCHIP) {
+		chips = this->numchips;
+		nrblocks = (int)(this->chipsize >> this->erase_shift);
+	} else {
+		chips = 1;
+		nrblocks = (int)(mtd->size >> this->erase_shift);
+	}	
+	
+	for (i = 0; i < chips; i++) {
+		if (td->options & NAND_BBT_ABSPAGE) {
+			block = td->pages[i] >> (this->erase_shift - this->page_shift);
+			block <<= 1;		
+			this->bbt[(block >> 3)] |= 0x2 << (block & 0x06);
+			continue;
+		} 
+		if (td->options & NAND_BBT_LASTBLOCK)
+			block = ((i + 1) * nrblocks) - td->maxblocks - 1;
+		else	
+			block = i * nrblocks;
+		block <<= 1;	
+		for (j = 0; j < td->maxblocks; j++) {
+			this->bbt[(block >> 3)] |= 0x2 << (block & 0x06);
+			block += 2;
+		}	
+	}
+}
 
 /**
  * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
@@ -600,7 +749,7 @@
 int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
 {
 	struct nand_chip *this = mtd->priv;
-	int len, res = 0, writeops = 0;
+	int len, res = 0;
 	uint8_t *buf;
 	struct nand_bbt_descr *td = this->bbt_td;
 	struct nand_bbt_descr *md = this->bbt_md;
@@ -640,48 +789,13 @@
 		res = search_read_bbts (mtd, buf, td, md);
 	}	
 
-	switch (res) {
-	case 0:	goto out;
-	case 1: writeops |= 0x01; goto writecheck;
-	case 2: writeops |= 0x02; goto writecheck;
-	case 3: writeops |= 0x03; break;
-	default: goto out;
-	}
-	/* Reset return value, as it could happen that it is not touched
-	 * anymore 
-	*/
-	res = 0;
-
-	/* Create the bad block table by scanning the device */
-	if (td->options & NAND_BBT_CREATE)
-		create_bbt (mtd, buf, bd);
-	else
-		goto out;
-
-	td->version = 1;
-	if (md)
-		md->version = 1;	
+	if (res) 
+		res = check_create (mtd, buf, bd);
 	
-writecheck:	
-	/* Write the bad block table to the device ? */
-	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-		res = write_bbt (mtd, buf, td, md);
-		if (res < 0)
-			goto out;
-	}
-	/* Write the mirror bad block table to the device ? */
-	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
-		res = write_bbt (mtd, buf, md, td);
-	}
+	/* Prevent the bbt regions from erasing / writing */
+	mark_bbt_region (mtd, td);
+	mark_bbt_region (mtd, md);
 	
-out:
-	/* Check, if the device size should be reduced automatically */
-	if ((td->options & (NAND_BBT_LASTBLOCK | NAND_BBT_REDUCESIZE)) ==
-		(NAND_BBT_LASTBLOCK | NAND_BBT_REDUCESIZE)) {
-		this->bbt_size = td->maxblocks << this->erase_shift;
-		mtd->size -= this->bbt_size;
-	}
-
 	kfree (buf);
 	return res;
 }
@@ -690,13 +804,15 @@
 /**
  * nand_update_bbt - [NAND Interface] update bad block table(s) 
  * @mtd:	MTD device structure
+ * @offs:	the offset of the newly marked block
  *
  * The function updates the bad block table(s)
 */
-int nand_update_bbt (struct mtd_info *mtd)
+int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
 {
 	struct nand_chip *this = mtd->priv;
 	int len, res = 0, writeops = 0;
+	int chip, chipsel;
 	uint8_t *buf;
 	struct nand_bbt_descr *td = this->bbt_td;
 	struct nand_bbt_descr *md = this->bbt_md;
@@ -716,32 +832,31 @@
 	
 	writeops = md != NULL ? 0x03 : 0x01;
 
-	td->version++;
+	/* Do we have a bbt per chip ? */
+	if (td->options & NAND_BBT_PERCHIP) {
+		chip = (int) (offs >> this->chip_shift);
+		chipsel = chip;
+	} else {
+		chip = 0;
+		chipsel = -1;
+	}
+
+	td->version[chip]++;
 	if (md)
-		md->version++;	
+		md->version[chip]++;	
 
-	/* Allow access to the bbt reserved blocks */
-	mtd->size += this->bbt_size;
-	
 	/* Write the bad block table to the device ? */
 	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-		res = write_bbt (mtd, buf, td, md);
+		res = write_bbt (mtd, buf, td, md, chipsel);
 		if (res < 0)
 			goto out;
 	}
 	/* Write the mirror bad block table to the device ? */
 	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
-		res = write_bbt (mtd, buf, md, td);
+		res = write_bbt (mtd, buf, md, td, chipsel);
 	}
 
 out:	
-	/* Check, if the device size should be reduced automatically */
-	if ((td->options & (NAND_BBT_LASTBLOCK | NAND_BBT_REDUCESIZE)) ==
-		(NAND_BBT_LASTBLOCK | NAND_BBT_REDUCESIZE)) {
-		this->bbt_size = td->maxblocks << this->erase_shift;
-		mtd->size -= this->bbt_size;
-	}
-
 	kfree (buf);
 	return res;
 }
@@ -797,7 +912,7 @@
 
 static struct nand_bbt_descr bbt_main_descr = {
 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE 
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_REDUCESIZE,
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
 	.offs =	8,
 	.len = 4,
 	.veroffs = 12,
@@ -807,7 +922,7 @@
 
 static struct nand_bbt_descr bbt_mirror_descr = {
 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE 
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_REDUCESIZE,
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
 	.offs =	8,
 	.len = 4,
 	.veroffs = 12,
@@ -865,5 +980,30 @@
 	}
 }
 
+/**
+ * nand_isbad_bbt - [NAND Interface] Check if a block is bad 
+ * @mtd:	MTD device structure
+ * @offs:	offset in the device
+ * @allowbbt:	allow access to bad block table region
+ *
+*/
+int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
+{
+	struct nand_chip *this = mtd->priv;
+	int block;
+	uint8_t	res;
+	
+	/* Get block number * 2 */
+	block = (int) (offs >> (this->erase_shift - 1));
+	res = this->bbt[block >> 3] & (0x3 << (block & 0x06));
+	res >>= (block & 0x06);
+	switch ((int)res) {
+	case 0x00:	return 0;
+	case 0x01:	return 1;
+	case 0x02:	return allowbbt ? 0 : 1;
+	}
+	return 1;
+}
+
 EXPORT_SYMBOL (nand_scan_bbt);
 EXPORT_SYMBOL (nand_default_bbt);

Index: autcpu12.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/autcpu12.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- autcpu12.c	26 May 2004 16:08:24 -0000	1.16
+++ autcpu12.c	28 May 2004 23:01:50 -0000	1.17
@@ -195,7 +195,7 @@
 	}
 	
 	/* Register the partitions */
-	switch(autcpu12_mtd->size + this->bbt_size){
+	switch(autcpu12_mtd->size){
 		case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
 		case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
 		case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; 





More information about the linux-mtd-cvs mailing list