u-boot-2014.10移植第22天----添加nand flash命令支持(四)

解决问题:

nand0: MTD Erase failure: -5  

drivers/mtd/nand/nand_bbt.c文件中初始化bbt

/*
     * Allocate memory (2bit per block) and clear the memory bad block
     * table.
     */
    this->bbt = kzalloc(len, GFP_KERNEL);
    if (!this->bbt)
        return -ENOMEM;

每个block用2个比特表示是否为坏块。

nand_scan_bbt

------>nand_memory_bbt

----------->create_bbt

---------------->scan_block_fast

下面的两个函数用来查看和标记上面说的每个block的2比特位。初步分析坏块时2比特位置为11。

static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
{
    uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
    entry >>= (block & BBT_ENTRY_MASK) * 2;
    return entry & BBT_ENTRY_MASK;
}

static inline void bbt_mark_entry(struct nand_chip *chip, int block,
        uint8_t mark)
{
    uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
    chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
}
我写了一个类似的程序来验证:

/*
 * Copyright: (C) 2014 fulinux <[email protected]>
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

uint8_t bbt[10];

void bbt_mark_entry(uint8_t *bbt, int block)
{
        uint8_t msk = (0x03 & 0x03) << ((block & 0x03) * 2);
            bbt[block >> 2] |= msk;
}

uint8_t bbt_get_entry(uint8_t *bbt, int block)
{
        uint8_t entry = bbt[block >> 2];
            entry >>= (block & 0x3) * 2;
                return entry & 0x3;
}

/*
 *  
 */
int main (int argc, char **argv)
{
    uint8_t a;
    bbt_mark_entry(bbt, 5);
    bbt_mark_entry(bbt, 7);
    bbt_mark_entry(bbt, 2);

    a = bbt_get_entry(bbt, 5);

    printf("a = %d\n", a);

    int i;
    for(i = 0; i < 10; i++){
        printf("0x%X\n", bbt[i]);
    }

    return 0;
} /* -----End of main()----- */

结果:

 ./bbt-test    
a = 3
0x30
0xCC
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0

二进制为:

1100110000110000

说明是正确的。


最后的解决方法:

在drivers/mtd/nand/nand_util.c文件中添加如下函数:

#define cpu_to_je16(x) (x)
#define cpu_to_je32(x) (x)

+ static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)
+ {
+         return 0;
+ }

再在nand_erase_opts函数中作如下修改:

int percent_complete = -1;
+ int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL;
const char *mtd_device = meminfo->name;

还有:

    if (opts->scrub) {
        erase.scrub = opts->scrub;
+         nand_block_bad_old = chip->block_bad;
+         chip->block_bad = nand_block_bad_scrub;
        /*
         * We don't need the bad block table anymore...
         * after scrub, there are no bad blocks left!
         */
        if (chip->bbt) {
            kfree(chip->bbt);
        }
        chip->bbt = NULL;
最后:

+     if(nand_block_bad_old){
+         chip->block_bad = nand_block_bad_old;
+     }

    if (opts->scrub)
        chip->scan_bbt(meminfo);

上面修改的意思是既然要将nand恢复出厂设置,那就不必要再去检测要擦出的函数是否是坏块了,所以把以前的那个检测是否是坏块的函数指针保存起来,在将其chip->block_bad指针指向了nand_block_bad_scrub函数,该函数什么都没做就返回了。同时将bbt清空,置为NULL,这在后面的

static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
                   int allowbbt)
{
    struct nand_chip *chip = mtd->priv;

    if (!chip->bbt){
        return chip->block_bad(mtd, ofs, getchip);
    }

    /* Return info from the table */
    return nand_isbad_bbt(mtd, ofs, allowbbt);
}
函数中因为chip->bbt == NULL而执行chip->block_bad函数,但是该函数在上面已经换成的了一个什么都没做的nand_block_bad_scrub函数。所以不会返回有坏块。在nand_erase_nand函数中就不会因为调用nand_block_checkbad函数而始终擦除不了被标识的会快而出现问题了。


恢复出厂设置后,再将前面chip->block_bad指针重新指向先前的函数,同时再分配bbt区域,并重新扫描一下是否有坏块。

演示:

[TQ2440 #] nand bad


Device 0 bad blocks:
[TQ2440 #] nand markbad 0
block 0x00000000 successfully marked as bad
[TQ2440 #] nand scrub 0 4000


NAND scrub: device 0 offset 0x0, size 0x4000
Warning: scrub option will erase all factory set bad blocks!
         There is no reliable way to recover them.
         Use this command only for testing purposes if you
         are sure of what you are doing!


Really scrub this NAND flash? <y/N>
y
Erasing at 0x0 -- 100% complete.
OK

明天继续。




















你可能感兴趣的:(ARM,erase,failure,u-boot,2440,mtd,2014.10,-5)