mtd/drivers/mtd/nand nand_bbt.c,1.3,1.4

gleixner at infradead.org gleixner at infradead.org
Thu May 27 06:37:14 EDT 2004


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

Modified Files:
	nand_bbt.c 
Log Message:
Make per chip table write work. Signed-off-by: Thomas Gleixner <tglx at linutronix.de>

Index: nand_bbt.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand_bbt.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- nand_bbt.c	26 May 2004 21:02:30 -0000	1.3
+++ nand_bbt.c	27 May 2004 10:37:11 -0000	1.4
@@ -401,144 +401,146 @@
 	struct erase_info einfo;
 	int i, j, res;
 	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
+	int chip, nrchips, bbtoffs;
 	uint8_t msk[4];
 	size_t retlen, len = 0;
 	loff_t to;
 	
-	/* There's no support for multichip per chip
-	 * bad block tables
-	 */
-	if (td->options & NAND_BBT_PERCHIP) { 
-		printk (KERN_ERR "No write support for per chip bad block tables\n");
-		return -EINVAL;
-	}
-#if 0
-	/* Absolute position given ? */
-	if (td->options & NAND_BBT_ABSPAGE)
-		return write_abs_bbt (mtd, buf, td);
-#endif	
-	/* Automatic placement of the bad block table */
+	/* Write bad block table per chip rather than per device ? */
+	if (td->options & NAND_BBT_PERCHIP)  
+		nrchips = this->numchips;
+	else
+		nrchips = 1;	
 
-	/* Search direction top -> down ? */
-	if (td->options & NAND_BBT_LASTBLOCK) {
-		startblock = (mtd->size >> this->erase_shift) -1;
-		dir = -1;
-	} else {
-		startblock = 0;	
-		dir = 1;
-	}	
-	
-	/* There was already a version of the table, reuse the page */
-	if (td->pages[0] != -1) {
-		page = td->pages[0];
-		goto write;
-	}	
-
-	for (i = 0; i < td->maxblocks; i++) {
-		int block = startblock + dir * i;
-		/* Check, if the block is bad */
-		if (this->bbt[block >> 2] & (0x03 << ((block << 1) & 0x6)))
-			continue;
-		page  = block << (this->erase_shift - this->page_shift);
-		/* Check, if the block is used by the mirror table */
-		if (!md || md->pages[0] != page)
+	/* Loop through the chips */
+	for (chip = 0; chip < nrchips; chip++) {
+		
+		/* There was already a version of the table, reuse the page 
+		 * This applies for absolute placement too, as we have the 
+		 * page nr. in td->pages.
+		 */
+		if (td->pages[chip] != -1) {
+			page = td->pages[chip];
 			goto write;
-	}
-	printk (KERN_ERR "No space left to write bad block table\n");
-	return -ENOSPC;
-	
+		}	
+
+		/* Automatic placement of the bad block table */
+		/* Search direction top -> down ? */
+		if (td->options & NAND_BBT_LASTBLOCK) {
+			startblock = ((mtd->size >> this->erase_shift) / nrchips);
+			startblock += chip * startblock - 1;
+			dir = -1;
+		} else {
+			startblock = chip * (this->chipsize >> this->erase_shift);
+			dir = 1;
+		}	
+
+		for (i = 0; i < td->maxblocks; i++) {
+			int block = startblock + dir * i;
+			/* Check, if the block is bad */
+			if (this->bbt[block >> 2] & (0x03 << ((block << 1) & 0x6)))
+				continue;
+			page  = block << (this->erase_shift - this->page_shift);
+			/* Check, if the block is used by the mirror table */
+			if (!md || md->pages[chip] != page)
+				goto write;
+		}
+		printk (KERN_ERR "No space left to write bad block table\n");
+		return -ENOSPC;
 write:	
 
-	/* 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;
-	default: return -EINVAL;
-	}
+		/* 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;
+		default: return -EINVAL;
+		}
 	
-	numblocks = mtd->size >> this->erase_shift;
-	to = ((loff_t) page) << this->page_shift;
+		numblocks = mtd->size >> this->erase_shift;
+		numblocks /= nrchips;
+		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 */
-		to &= ~((loff_t) ((1 << this->erase_shift) - 1));
-		res = mtd->read_ecc (mtd, to, len, &retlen, buf, NULL, this->autooob);
-		len = 1 << this->erase_shift;
-		if (res < 0) {
-			if (retlen != len) {
-				printk (KERN_INFO "nand_bbt: Error reading block for writing the bad block table\n");
-				return res;
+		/* Must we save the block contents ? */
+		if (td->options & NAND_BBT_SAVECONTENT) {
+			/* Make it block aligned */
+			to &= ~((loff_t) ((1 << this->erase_shift) - 1));
+			res = mtd->read_ecc (mtd, to, len, &retlen, buf, NULL, this->autooob);
+			len = 1 << this->erase_shift;
+			if (res < 0) {
+				if (retlen != len) {
+					printk (KERN_INFO "nand_bbt: Error reading block for writing the bad block table\n");
+					return res;
+				}
+				printk (KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n");
+			}
+			res = mtd->read_ecc (mtd, to, (len >> this->page_shift) * mtd->oobsize, &retlen, buf, NULL, this->autooob);
+			if (res < 0) {
+				if (retlen != len) {
+					printk (KERN_INFO "nand_bbt: Error reading oob data for writing the bad block table\n");
+					return res;
+				}
+				printk (KERN_WARNING "nand_bbt: ECC error while reading oob data for writing bad block table\n");
+			}
+			/* Calc the byte offset in the buffer */
+			offs = page - (int)(to >> this->page_shift);
+			offs <<= this->page_shift;
+			/* Preset the bbt area with 0xff */
+			memset (&buf[offs], 0xff, (size_t)(numblocks >> sft));
+		} else {
+			/* Calc length */
+			len = (size_t) (numblocks >> sft);
+			/* Make it page aligned ! */
+			len += len % mtd->oobblock;
+			/* Preset the buffer with 0xff */
+			memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize);
+			offs = 0;
+			/* Pattern is located in oob area of first page */
+			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);
 			}
-			printk (KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n");
 		}
-		res = mtd->read_ecc (mtd, to, (len >> this->page_shift) * mtd->oobsize, &retlen, buf, NULL, this->autooob);
-		if (res < 0) {
-			if (retlen != len) {
-				printk (KERN_INFO "nand_bbt: Error reading oob data for writing the bad block table\n");
-				return res;
+	
+		/* walk through the memory table */
+		for (i = 0; i < numblocks; ) {
+			uint8_t dat;
+			dat = this->bbt[bbtoffs + (i >> 2)];
+			for (j = 0; j < 4; j++ , i++) {
+				int sftcnt = (i << (3 - sft)) & sftmsk;
+				buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
+				dat >>= 2;
 			}
-			printk (KERN_WARNING "nand_bbt: ECC error while reading oob data for writing bad block table\n");
 		}
-		/* Calc the byte offset in the buffer */
-		offs = page - (int)(to >> this->page_shift);
-		offs <<= this->page_shift;
-		/* Preset the bbt area with 0xff */
-		memset (&buf[offs], 0xff, (size_t)(numblocks >> sft));
-	} else {
-		/* Calc length */
-		len = (size_t) (numblocks >> sft);
-		/* Make it page aligned ! */
-		len += len % mtd->oobblock;
-		/* Preset the buffer with 0xff */
-		memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize);
-		offs = 0;
-		/* Pattern is located in oob area of first page */
-		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);
-		}
-	}
-	
-	/* walk through the memory table */
-	for (i = 0; i < numblocks; ) {
-		uint8_t dat;
-		dat = this->bbt[i >> 2];
-		for (j = 0; j < 4; j++ , i++) {
-			int sftcnt = (i << (3 - sft)) & sftmsk;
-			buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
-			dat >>= 2;
-		}
-	}
-	
-	memset (&einfo, 0, sizeof (einfo));
-	einfo.mtd = mtd;
-	einfo.addr = to;
-	einfo.len = 1 << this->erase_shift;
-	res = mtd->erase (mtd, &einfo);
-	if (res < 0) {
-		printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
-		return res;
-	}
-	
-	memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
-	oobinfo.useecc = MTD_NANDECC_PLACE;
-	
-	res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
-	if (res < 0) {
-		printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
-		return res;
-	}
-	printk (KERN_DEBUG "Bad block table written to 0x%08x, version %d\n", 
-		(unsigned int) to, td->version);
+		
+		memset (&einfo, 0, sizeof (einfo));
+		einfo.mtd = mtd;
+		einfo.addr = to;
+		einfo.len = 1 << this->erase_shift;
+		res = mtd->erase (mtd, &einfo);
+		if (res < 0) {
+			printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
+			return res;
+		}
 	
-	/* Mark it as used */
-	td->pages[0] = page;
+		memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
+		oobinfo.useecc = MTD_NANDECC_PLACE;
 	
+		res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
+		if (res < 0) {
+			printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
+			return res;
+		}
+		printk (KERN_DEBUG "Bad block table written to 0x%08x, version %d\n", 
+			(unsigned int) to, td->version);
+	
+		/* Mark it as used */
+		td->pages[chip] = page;
+	}	
 	return 0;
 }
 





More information about the linux-mtd-cvs mailing list