分类: LINUX
2013-03-21 23:58:40
Arm-linux东东nand之8: nand_scan_tail中
应该叹一口气了. 不得不佩服nand_scan_tail.因为下面要说坏块扫描了.
…………….
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
!(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
switch(chip->ecc.steps) {
case 2:
mtd->subpage_sft = 1;
break;
case 4:
case 8:
mtd->subpage_sft = 2;
break;
}
}
chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
/* Initialize state */
chip->state = FL_READY;
/* De-select the device */
chip->select_chip(mtd, -1);
/* Invalidate the pagebuffer reference */
chip->pagebuf = -1;
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->sync = nand_sync;
mtd->lock = NULL;
mtd->unlock = NULL;
mtd->suspend = nand_suspend;
mtd->resume = nand_resume;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
/* propagate ecc.layout to mtd_info */
mtd->ecclayout = chip->ecc.layout;
/* Check, if we should skip the bad block table scan */
if (chip->options & NAND_SKIP_BBTSCAN)
return 0;
/* Build bad block table */
return chip->scan_bbt(mtd);
………………..
都是一些赋值没什么.看最后一句.当时我还以后它应该不会很长.可惜错了…
在nand_set_defaults中应该有下面这个吧
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
………………
于是:
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);
}
static struct nand_bbt_descr smallpage_memorybased = {
.options = NAND_BBT_SCAN2NDPAGE,
.offs = 5,
.len = 1,
.pattern = scan_ff_pattern
};
…
红色的那几个标志我们没有吧.因为它们是上面说的”变态”NAND的专利.
OK 最后else会执行.
badblock_pattern是指向smallpage_memorybased;的
go go
Go go
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;
}
…………………………..
唉.真长呀.在大学学了三年的C语言.书上从来没有看过这么长的函数.
看红色的那一段.
现在要扫描坏快.你总应该分出一些内存来记着那块是坏的吧.
本来一块一字节很好理解
mtd->size >> this->bbt_erase_shift就这样.
但本着节约的精神.人家说一块2个bit.于是除于4. 8bit由4个2bit组成吗!
我就不理解了,为什么再省一点一块1bit呢.我的64M的RAM也不多呀.
于是就成了这样子: len = mtd->size >> (this->bbt_erase_shift + 2);
看褐色的那一段,能成立吧.上面刚做过这样的this->bbt_td = NULL;
看到return res;狂喜,下面的不用看了.
…………….
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);
}
……………………………………………………
请注意这里取消了NAND_BBT_SCANEMPTY.
…………………….
static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *bd, int chip)
{
struct nand_chip *this = mtd->priv;
int i, numblocks, len, scanlen;
int startblock;
loff_t from;
size_t readlen;
printk(KERN_INFO "Scanning device for bad blocks\n");
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;
}
…………………….
一块不是由几个页组成的吧.那扫描一块是不是要全部页都要检查一下呢.还是?
NAND_BBT_SCANALLPAGES表示全部页都要检查.这里没有这个标志.
NAND_BBT_SCAN2NDPAGE表示头二页检查一下就行了.这里设了.
static struct nand_bbt_descr smallpage_memorybased = {
.options = NAND_BBT_SCAN2NDPAGE,
记得不.
………………………
if (!(bd->options & NAND_BBT_SCANEMPTY)) {
/* We need only read few bytes from the OOB area */
scanlen = 0;
readlen = bd->len;
} else {
/* Full page content should be read */
scanlen = mtd->writesize + mtd->oobsize;
readlen = len * mtd->writesize;
}
………………………………………
以前取消掉了这个NAND_BBT_SCANEMPTY
看下这个: We need only read few bytes from the OOB area.OK
……………….
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 -EINVAL;
}
numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
startblock = chip * numblocks;
numblocks += startblock;
from = startblock << (this->bbt_erase_shift - 1);
}
………………
Chip是不等于-1的.numblocks = mtd->size >> (this->bbt_erase_shift - 1);这里乘以2,因为少移一位了.
startblock = 0;表示第0块开始
………………..
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;
…………………
进入for 循环了.注意了i+=2是吧.为什么上面乘以2这里又每次加2呢.
看下面这个句子:
this->bbt[i >> 3] |= 0x03 << (i & 0x6);
闭着眼睛都能知道就是找到那个块2 bit位,如果还不懂.那就把数值代进去.
From每次就加一个块值了.
这里执行
else
ret = scan_block_fast(mtd, bd, from, buf, len);
于是就要看scan_block_fast.