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