📄 nand_bbt.c
字号:
if (td->version[i] == md->version[i]) { rd = td; if (!(td->options & NAND_BBT_VERSION)) rd2 = md; goto writecheck; } if (((int8_t) (td->version[i] - md->version[i])) > 0) { 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); /* If they weren't versioned, read both. */ if (rd2) read_abs_bbt(mtd, buf, rd2, 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, update; uint8_t oldval, newval; /* Do we have a bbt per chip ? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); } else { chips = 1; nrblocks = (int)(mtd->size >> this->bbt_erase_shift); } for (i = 0; i < chips; i++) { if ((td->options & NAND_BBT_ABSPAGE) || !(td->options & NAND_BBT_WRITE)) { if (td->pages[i] == -1) continue; block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); block <<= 1; oldval = this->bbt[(block >> 3)]; newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; if ((oldval != newval) && td->reserved_block_code) nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1)); continue; } update = 0; if (td->options & NAND_BBT_LASTBLOCK) block = ((i + 1) * nrblocks) - td->maxblocks; else block = i * nrblocks; block <<= 1; for (j = 0; j < td->maxblocks; j++) { oldval = this->bbt[(block >> 3)]; newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; if (oldval != newval) update = 1; block += 2; } /* If we want reserved blocks to be recorded to flash, and some new ones have been marked, then we need to update the stored bbts. This should only happen once. */ if (update && td->reserved_block_code) nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1)); }}/** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) * @mtd: MTD device structure * @bd: descriptor for the good/bad block search pattern * * The function checks, if a bad block table(s) is/are already * available. If not it scans the device for manufacturer * marked good / bad blocks and writes the bad block table(s) to * the selected place. * * The bad block table memory is allocated here. It must be freed * by calling the nand_free_bbt function. **/int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd){ struct nand_chip *this = mtd->priv; int len, res = 0; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; len = mtd->size >> (this->bbt_erase_shift + 2); /* Allocate memory (2bit per block) and clear the memory bad block table */ this->bbt = kzalloc(len, GFP_KERNEL); if (!this->bbt) { printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); return -ENOMEM; } /* If no primary table decriptor is given, scan the device * to build a memory based bad block table */ if (!td) { if ((res = nand_memory_bbt(mtd, bd))) { printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); kfree(this->bbt); this->bbt = NULL; } return res; } /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; buf = vmalloc(len); if (!buf) { printk(KERN_ERR "nand_bbt: Out of memory\n"); kfree(this->bbt); this->bbt = NULL; return -ENOMEM; } /* Is the bbt at a given page ? */ if (td->options & NAND_BBT_ABSPAGE) { res = read_abs_bbts(mtd, buf, td, md); } else { /* Search the bad block table using a pattern in oob */ res = search_read_bbts(mtd, buf, td, md); } if (res) res = check_create(mtd, buf, bd); /* Prevent the bbt regions from erasing / writing */ mark_bbt_region(mtd, td); if (md) mark_bbt_region(mtd, md); vfree(buf); return res;}/** * 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, 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; if (!this->bbt || !td) return -EINVAL; len = mtd->size >> (this->bbt_erase_shift + 2); /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; buf = kmalloc(len, GFP_KERNEL); if (!buf) { printk(KERN_ERR "nand_update_bbt: Out of memory\n"); return -ENOMEM; } writeops = md != NULL ? 0x03 : 0x01; /* 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[chip]++; /* 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) 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, chipsel); } out: kfree(buf); return res;}/* Define some generic bad / good block scan pattern which are used * while scanning a device for factory marked good / bad blocks. */static uint8_t scan_ff_pattern[] = { 0xff, 0xff };static struct nand_bbt_descr smallpage_memorybased = { .options = NAND_BBT_SCAN2NDPAGE, .offs = 5, .len = 1, .pattern = scan_ff_pattern};static struct nand_bbt_descr largepage_memorybased = { .options = 0, .offs = 0, .len = 2, .pattern = scan_ff_pattern};static struct nand_bbt_descr smallpage_flashbased = { .options = NAND_BBT_SCAN2NDPAGE, .offs = 5, .len = 1, .pattern = scan_ff_pattern};static struct nand_bbt_descr largepage_flashbased = { .options = NAND_BBT_SCAN2NDPAGE, .offs = 0, .len = 2, .pattern = scan_ff_pattern};static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };static struct nand_bbt_descr agand_flashbased = { .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, .offs = 0x20, .len = 6, .pattern = scan_agand_pattern};/* Generic flash bbt decriptors*/static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };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_PERCHIP, .offs = 8, .len = 4, .veroffs = 12, .maxblocks = 4, .pattern = bbt_pattern};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_PERCHIP, .offs = 8, .len = 4, .veroffs = 12, .maxblocks = 4, .pattern = mirror_pattern};/** * nand_default_bbt - [NAND Interface] Select a default bad block table for the device * @mtd: MTD device structure * * This function selects the default bad block table * support for the device and calls the nand_scan_bbt function **/int nand_default_bbt(struct mtd_info *mtd){ struct nand_chip *this = mtd->priv; /* Default for AG-AND. We must use a flash based * bad block table as the devices have factory marked * _good_ blocks. Erasing those blocks leads to loss * of the good / bad information, so we _must_ store * this information in a good / bad table during * startup */ if (this->options & NAND_IS_AND) { /* Use the default pattern descriptors */ if (!this->bbt_td) { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; } this->options |= NAND_USE_FLASH_BBT; return nand_scan_bbt(mtd, &agand_flashbased); } /* Is a flash based bad block table requested ? */ if (this->options & NAND_USE_FLASH_BBT) { /* Use the default pattern descriptors */ if (!this->bbt_td) { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; } if (!this->badblock_pattern) { this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased; } } else { this->bbt_td = NULL; this->bbt_md = NULL; if (!this->badblock_pattern) { this->badblock_pattern = (mtd->writesize > 512) ? &largepage_memorybased : &smallpage_memorybased; } } return nand_scan_bbt(mtd, this->badblock_pattern);}/** * 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->bbt_erase_shift - 1)); res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", (unsigned int)offs, block >> 1, res); 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -