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