注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

Linux MTD子系统学习5—s3c24xx_nand_probe()函数之六  

2012-01-16 19:19:11|  分类: LINUX内核驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

Linux MTD子系统学习5—s3c24xx_nand_probe()函数之六

s3c2410_nand_update_chip函数比较简单,童鞋们自己到网上查找资料,看这个重量级的长跑运动员nand_scan_tail。

/**

 * nand_scan_tail - [NAND Interface] Scan for the NAND device

 * @mtd:        MTD device structure

 *

 * This is the second phase of the normal nand_scan() function. It

 * fills out all the uninitialized function pointers with the defaults

 * and scans for a bad block table if appropriate.

 */

int nand_scan_tail(struct mtd_info *mtd)

{

    int i;

    struct nand_chip *chip = mtd->priv;

 

    if (!(chip->options & NAND_OWN_BUFFERS))

        chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);

    if (!chip->buffers)

        return -ENOMEM;

//这里oob_poi就是指向databuf的第512个字节.这个地址是放ECC数据的..下面会看到.

 

    /* Set the internal oob buffer location, just after the page data */

    chip->oob_poi = chip->buffers->databuf + mtd->writesize;

 

    /*

     * If no default placement scheme is given, select an appropriate one

     */

    if (!chip->ecc.layout) {

        switch (mtd->oobsize) {

        case 8:

            chip->ecc.layout = &nand_oob_8;

            break;

        case 16:

            chip->ecc.layout = &nand_oob_16;

            break;

        case 64:

            chip->ecc.layout = &nand_oob_64;

            break;

        case 128:

            chip->ecc.layout = &nand_oob_128;

            break;

        default:

            printk(KERN_WARNING "No oob scheme defined for "

                   "oobsize %d\n", mtd->oobsize);

            BUG();

        }

    }

 

    if (!chip->write_page)

        chip->write_page = nand_write_page;

 

    /*

     * check ECC mode, default to software if 3byte/512byte hardware ECC is

     * selected and we have 256 byte pagesize fallback to software ECC

     */

 

    switch (chip->ecc.mode) {

    case NAND_ECC_HW_OOB_FIRST:

        /* Similar to NAND_ECC_HW, but a separate read_page handle */

        if (!chip->ecc.calculate || !chip->ecc.correct ||

             !chip->ecc.hwctl) {

            printk(KERN_WARNING "No ECC functions supplied; "

                   "Hardware ECC not possible\n");

            BUG();

        }

        if (!chip->ecc.read_page)

            chip->ecc.read_page = nand_read_page_hwecc_oob_first;

 

    case NAND_ECC_HW:

        /* Use standard hwecc read page function ? */

        if (!chip->ecc.read_page)

            chip->ecc.read_page = nand_read_page_hwecc;

        if (!chip->ecc.write_page)

            chip->ecc.write_page = nand_write_page_hwecc;

        if (!chip->ecc.read_page_raw)

            chip->ecc.read_page_raw = nand_read_page_raw;

        if (!chip->ecc.write_page_raw)

            chip->ecc.write_page_raw = nand_write_page_raw;

        if (!chip->ecc.read_oob)

            chip->ecc.read_oob = nand_read_oob_std;

        if (!chip->ecc.write_oob)

            chip->ecc.write_oob = nand_write_oob_std;

 

    case NAND_ECC_HW_SYNDROME:

        if ((!chip->ecc.calculate || !chip->ecc.correct ||

             !chip->ecc.hwctl) &&

            (!chip->ecc.read_page ||

             chip->ecc.read_page == nand_read_page_hwecc ||

             !chip->ecc.write_page ||

             chip->ecc.write_page == nand_write_page_hwecc)) {

            printk(KERN_WARNING "No ECC functions supplied; "

                   "Hardware ECC not possible\n");

            BUG();

        }

        /* Use standard syndrome read/write page function ? */

        if (!chip->ecc.read_page)

            chip->ecc.read_page = nand_read_page_syndrome;

        if (!chip->ecc.write_page)

            chip->ecc.write_page = nand_write_page_syndrome;

        if (!chip->ecc.read_page_raw)

            chip->ecc.read_page_raw = nand_read_page_raw_syndrome;

        if (!chip->ecc.write_page_raw)

            chip->ecc.write_page_raw = nand_write_page_raw_syndrome;

        if (!chip->ecc.read_oob)

            chip->ecc.read_oob = nand_read_oob_syndrome;

        if (!chip->ecc.write_oob)

            chip->ecc.write_oob = nand_write_oob_syndrome;

 

        if (mtd->writesize >= chip->ecc.size)

            break;

        printk(KERN_WARNING "%d byte HW ECC not possible on "

               "%d byte page size, fallback to SW ECC\n",

               chip->ecc.size, mtd->writesize);

        chip->ecc.mode = NAND_ECC_SOFT;

 

    case NAND_ECC_SOFT:

        chip->ecc.calculate = nand_calculate_ecc;

        chip->ecc.correct = nand_correct_data;

        chip->ecc.read_page = nand_read_page_swecc;

        chip->ecc.read_subpage = nand_read_subpage;

        chip->ecc.write_page = nand_write_page_swecc;

        chip->ecc.read_page_raw = nand_read_page_raw;

        chip->ecc.write_page_raw = nand_write_page_raw;

        chip->ecc.read_oob = nand_read_oob_std;

        chip->ecc.write_oob = nand_write_oob_std;

        if (!chip->ecc.size)

            chip->ecc.size = 256;

        chip->ecc.bytes = 3;

        break;

 

    case NAND_ECC_NONE:

        printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "

               "This is not recommended !!\n");

        chip->ecc.read_page = nand_read_page_raw;

        chip->ecc.write_page = nand_write_page_raw;

        chip->ecc.read_oob = nand_read_oob_std;

        chip->ecc.read_page_raw = nand_read_page_raw;

        chip->ecc.write_page_raw = nand_write_page_raw;

        chip->ecc.write_oob = nand_write_oob_std;

        chip->ecc.size = mtd->writesize;

        chip->ecc.bytes = 0;

        break;

 

    default:

        printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",

               chip->ecc.mode);

        BUG();

    }

 

    /*

     * The number of bytes available for a client to place data into

     * the out of band area

     */

    chip->ecc.layout->oobavail = 0;

    for (i = 0; chip->ecc.layout->oobfree[i].length

            && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)

        chip->ecc.layout->oobavail +=

            chip->ecc.layout->oobfree[i].length;

    mtd->oobavail = chip->ecc.layout->oobavail;

 

    /*

     * Set the number of read / write steps for one page depending on ECC

     * mode

     */

    chip->ecc.steps = mtd->writesize / chip->ecc.size;

    if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {

        printk(KERN_WARNING "Invalid ecc parameters\n");

        BUG();

    }

    chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;

 

    /*

     * Allow subpage writes up to ecc.steps. Not possible for MLC

     * FLASH.

     */

    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:

        case 16:

            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);

}

一片片的,眼花缭乱,从头来吧。先除去stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);就是调用:s3c2410_nand_correct_data这个函数进行的ECC的检验,这个不是重点,只抓关键。

除了一些必要的同仁外,看最后这行return chip->scan_bbt(mtd);在前面我们知道

在nand_set_defaults中:

       if (!chip->scan_bbt)

              chip->scan_bbt = nand_default_bbt;

/**

 * 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);

}

if (this->options & NAND_IS_AND)是和前面注册一大片那个目前知道的芯片有关系,有一个芯片比较特殊,所以就用这个业判断,大家可以回去看看nand_flash_ids[]里那个AND的东东。

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;

}

 

看红色的那一段.

现在要扫描坏快.你总应该分出一些内存来记着那块是坏的吧.

本来一块一字节很好理解

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;

 

 

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.

  评论这张
 
阅读(1376)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017