📄 nand_bbt.c
字号:
/* * drivers/mtd/nand_bbt.c * * Overview: * Bad block table support for the NAND driver * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Description: * * When nand_scan_bbt is called, then it tries to find the bad block table * depending on the options in the bbt descriptor(s). If a bbt is found * then the contents are read and the memory based bbt is created. If a * mirrored bbt is selected then the mirror is searched too and the * versions are compared. If the mirror has a greater version number * than the mirror bbt is used to build the memory based bbt. * If the tables are not versioned, then we "or" the bad block information. * If one of the bbt's is out of date or does not exist it is (re)created. * If no bbt exists at all then the device is scanned for factory marked * good / bad blocks and the bad block tables are created. * * For manufacturer created bbts like the one found on M-SYS DOC devices * the bbt is searched and read but never created * * The autogenerated bad block table is located in the last good blocks * of the device. The table is mirrored, so it can be updated eventually. * The table is marked in the oob area with an ident pattern and a version * number which indicates which of both tables is more up to date. * * The table uses 2 bits per block * 11b: block is good * 00b: block is factory marked bad * 01b, 10b: block is marked bad due to wear * * The memory bad block table uses the following scheme: * 00b: block is good * 01b: block is marked bad due to wear * 10b: block is reserved (to protect the bbt area) * 11b: block is factory marked bad * * Multichip devices like DOC store the bad block info per floor. * * Following assumptions are made: * - bbts start at a page boundary, if autolocated on a block boundary * - the space neccecary for a bbt in FLASH does not exceed a block boundary * */#include <common.h>#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)#include <malloc.h>#include <linux/mtd/compat.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <asm/errno.h>/** * check_pattern - [GENERIC] check if a pattern is in the buffer * @buf: the buffer to search * @len: the length of buffer to search * @paglen: the pagelength * @td: search pattern descriptor * * Check for a pattern at the given place. Used to search bad block * tables and good / bad block identifiers. * If the SCAN_EMPTY option is set then check, if all bytes except the * pattern area contain 0xff **/static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td){ int i, end; uint8_t *p = buf; end = paglen + td->offs; if (td->options & NAND_BBT_SCANEMPTY) { for (i = 0; i < end; i++) { if (p[i] != 0xff) return -1; } } p += end; /* Compare the pattern */ for (i = 0; i < td->len; i++) { if (p[i] != td->pattern[i]) return -1; } p += td->len; end += td->len; if (td->options & NAND_BBT_SCANEMPTY) { for (i = end; i < len; i++) { if (*p++ != 0xff) return -1; } } return 0;}/** * read_bbt - [GENERIC] Read the bad block table starting from page * @mtd: MTD device structure * @buf: temporary buffer * @page: the starting page * @num: the number of bbt descriptors to read * @bits: number of bits per block * @offs: offset in the memory table * @reserved_block_code: Pattern to identify reserved blocks * * Read the bad block table starting from page. * */static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, int bits, int offs, int reserved_block_code){ int res, i, j, act = 0; struct nand_chip *this = mtd->priv; size_t retlen, len, totlen; loff_t from; uint8_t msk = (uint8_t) ((1 << bits) - 1); totlen = (num * bits) >> 3; from = ((loff_t)page) << this->page_shift; while (totlen) { len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); if (res < 0) { if (retlen != len) { printk (KERN_INFO "nand_bbt: Error reading bad block table\n"); return res; } printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); } /* Analyse data */ for (i = 0; i < len; i++) { uint8_t dat = buf[i]; for (j = 0; j < 8; j += bits, act += 2) { uint8_t tmp = (dat >> j) & msk; if (tmp == msk) continue; if (reserved_block_code && (tmp == reserved_block_code)) { printk (KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); continue; } /* 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->bbt_erase_shift); /* Factory marked bad or worn out ? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); else this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); } } totlen -= len; from += len; } return 0;}/** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page * @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, int chip){ struct nand_chip *this = mtd->priv; 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++) { if (chip == -1 || chip == i) res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); if (res) return res; offs += this->chipsize >> (this->bbt_erase_shift + 2); } } else { res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); if (res) return res; } return 0;}/** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page * @mtd: MTD device structure * @buf: temporary buffer * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * * Read the bad block table(s) for all chips starting at a given page * We assume that the bbt bits are in consecutive order. **/static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md){ struct nand_chip *this = mtd->priv; /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); td->version[0] = buf[mtd->oobblock + td->veroffs]; printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); md->version[0] = buf[mtd->oobblock + md->veroffs]; printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } return 1;}/** * create_bbt - [GENERIC] Create a bad block table by scanning the device * @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, int chip){ struct nand_chip *this = mtd->priv; int i, j, numblocks, len, scanlen; int startblock; loff_t from; size_t readlen, ooblen; if (bd->options & NAND_BBT_SCANALLPAGES) len = 1 << (this->bbt_erase_shift - this->page_shift); else { if (bd->options & NAND_BBT_SCAN2NDPAGE) len = 2; else len = 1; } scanlen = mtd->oobblock + mtd->oobsize; readlen = len * mtd->oobblock; ooblen = len * mtd->oobsize; 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->bbt_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->bbt_erase_shift - 1); startblock = chip * numblocks; numblocks += startblock; from = startblock << (this->bbt_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[j * scanlen], scanlen, mtd->oobblock, bd)) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); break; } } i += 2; from += (1 << this->bbt_erase_shift); }}/** * 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 neccecary 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->oobblock + mtd->oobsize; int bbtblocks; /* 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -