📄 nand_bbt.c
字号:
chip + 1, this->numchips); return -EINVAL; } numblocks = this->chipsize >> (this->bbt_erase_shift - 1); startblock = chip * numblocks; numblocks += startblock; from = startblock << (this->bbt_erase_shift - 1); } for (i = startblock; i < numblocks;) { int ret; if (bd->options & NAND_BBT_SCANALLPAGES) ret = scan_block_full(mtd, bd, from, buf, readlen, scanlen, len); else ret = scan_block_fast(mtd, bd, from, buf, len); if (ret < 0) return ret; if (ret) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, (unsigned int)from); mtd->ecc_stats.badblocks++; } i += 2; from += (1 << this->bbt_erase_shift); } return 0;}/** * search_bbt - [GENERIC] scan the device for a specific bad block table * @mtd: MTD device structure * @buf: temporary buffer * @td: descriptor for the bad block table * * Read the bad block table by searching for a given ident pattern. * Search is preformed either from the beginning up or from the end of * the device downwards. The search starts always at the start of a * block. * If the option NAND_BBT_PERCHIP is given, each chip is searched * for a bbt, which contains the bad block information of this chip. * This is necessary to provide support for certain DOC devices. * * The bbt ident pattern resides in the oob area of the first page * in a block. */static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td){ struct nand_chip *this = mtd->priv; int i, chips; int bits, startblock, block, dir; int scanlen = mtd->writesize + mtd->oobsize; int bbtblocks; int blocktopage = this->bbt_erase_shift - this->page_shift; /* Search direction top -> down ? */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = (mtd->size >> this->bbt_erase_shift) - 1; dir = -1; } else { startblock = 0; dir = 1; } /* Do we have a bbt per chip ? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; bbtblocks = this->chipsize >> this->bbt_erase_shift; startblock &= bbtblocks - 1; } else { chips = 1; bbtblocks = mtd->size >> this->bbt_erase_shift; } /* Number of bits for each erase block in the bbt */ bits = td->options & NAND_BBT_NRBITS_MSK; 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++) { int actblock = startblock + dir * block; loff_t offs = actblock << this->bbt_erase_shift; /* Read first page */ scan_read_raw(mtd, buf, offs, mtd->writesize); if (!check_pattern(buf, scanlen, mtd->writesize, td)) { td->pages[i] = actblock << blocktopage; if (td->options & NAND_BBT_VERSION) { td->version[i] = buf[mtd->writesize + td->veroffs]; } break; } } startblock += this->chipsize >> this->bbt_erase_shift; } /* Check, if we found a bbt for each requested chip */ for (i = 0; i < chips; i++) { if (td->pages[i] == -1) printk(KERN_WARNING "Bad block table not found for chip %d\n", i); else printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); } return 0;}/** * search_read_bbts - [GENERIC] scan the device for bad block table(s) * @mtd: MTD device structure * @buf: temporary buffer * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * * Search and read the bad block table(s)*/static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md){ /* Search the primary table */ search_bbt(mtd, buf, td); /* Search the mirror table */ if (md) search_bbt(mtd, buf, md); /* Force result check */ return 1;}/** * write_bbt - [GENERIC] (Re)write the bad block table * * @mtd: MTD device structure * @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, int chipsel){ struct nand_chip *this = mtd->priv; struct erase_info einfo; int i, j, res, chip = 0; int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; int nrchips, bbtoffs, pageoffs, ooboffs; uint8_t msk[4]; uint8_t rcode = td->reserved_block_code; size_t retlen, len = 0; loff_t to; struct mtd_oob_ops ops; ops.ooblen = mtd->oobsize; ops.ooboffs = 0; ops.datbuf = NULL; ops.mode = MTD_OOB_PLACE; if (!rcode) rcode = 0xff; /* Write bad block table per chip rather than per device ? */ if (td->options & NAND_BBT_PERCHIP) { numblocks = (int)(this->chipsize >> this->bbt_erase_shift); /* Full device write or specific chip ? */ if (chipsel == -1) { nrchips = this->numchips; } else { nrchips = chipsel + 1; chip = chipsel; } } else { numblocks = (int)(mtd->size >> this->bbt_erase_shift); nrchips = 1; } /* Loop through the chips */ 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 * page nr. in td->pages. */ if (td->pages[chip] != -1) { page = td->pages[chip]; goto write; } /* Automatic placement of the bad block table */ /* Search direction top -> down ? */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = numblocks * (chip + 1) - 1; dir = -1; } else { startblock = chip * numblocks; dir = 1; } for (i = 0; i < td->maxblocks; i++) { int block = startblock + dir * i; /* Check, if the block is bad */ switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) { case 0x01: case 0x03: continue; } page = block << (this->bbt_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; msk[2] = ~rcode; switch (bits) { case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[3] = 0x01; break; case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[3] = 0x03; break; case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[3] = 0x0f; break; case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[3] = 0xff; break; default: return -EINVAL; } bbtoffs = chip * (numblocks >> 2); 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->bbt_erase_shift) - 1)); len = 1 << this->bbt_erase_shift; res = mtd->read(mtd, to, len, &retlen, buf); 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"); } /* Read oob data */ ops.ooblen = (len >> this->page_shift) * mtd->oobsize; ops.oobbuf = &buf[len]; res = mtd->read_oob(mtd, to + mtd->writesize, &ops); if (res < 0 || ops.oobretlen != ops.ooblen) goto outerr; /* Calc the byte offset in the buffer */ pageoffs = page - (int)(to >> this->page_shift); offs = pageoffs << this->page_shift; /* Preset the bbt area with 0xff */ memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); ooboffs = len + (pageoffs * mtd->oobsize); } else { /* Calc length */ len = (size_t) (numblocks >> sft); /* Make it page aligned ! */ len = (len + (mtd->writesize - 1)) & ~(mtd->writesize - 1); /* Preset the buffer with 0xff */ memset(buf, 0xff, len + (len >> this->page_shift)* mtd->oobsize); offs = 0; ooboffs = len; /* Pattern is located in oob area of first page */ memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); } if (td->options & NAND_BBT_VERSION) buf[ooboffs + td->veroffs] = td->version[chip]; /* 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; /* Do not store the reserved bbt blocks ! */ buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); dat >>= 2; } } memset(&einfo, 0, sizeof(einfo)); einfo.mtd = mtd; einfo.addr = (unsigned long)to; einfo.len = 1 << this->bbt_erase_shift; res = nand_erase_nand(mtd, &einfo, 1); if (res < 0) goto outerr; res = scan_write_bbt(mtd, to, len, buf, &buf[len]); if (res < 0) goto outerr; printk(KERN_DEBUG "Bad block table written to 0x%08x, version " "0x%02X\n", (unsigned int)to, td->version[chip]); /* Mark it as used */ td->pages[chip] = page; } return 0; outerr: printk(KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); return res;}/** * nand_memory_bbt - [GENERIC] create a memory based bad block table * @mtd: MTD device structure * @bd: descriptor for the good/bad block search pattern * * The function creates a memory based bbt by scanning the device * for manufacturer / software marked good / bad blocks*/static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd){ struct nand_chip *this = mtd->priv; bd->options &= ~NAND_BBT_SCANEMPTY; return create_bbt(mtd, this->buffers->databuf, bd, -1);}/** * check_create - [GENERIC] create and write bbt(s) if necessary * @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 necessary * Creation is necessary if no bbt was found for the chip/device * Update is necessary 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, *rd2; /* 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; rd2 = 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; td->version[i] = md->version[i]; writeops = 1; goto writecheck; } if (md->pages[i] == -1) { rd = td; md->version[i] = td->version[i]; writeops = 2; goto writecheck; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -