32-Openwrt nand flash坏块管理nmbm功能支持

nand flash很容易有坏块出现,一旦出现坏块数据就会丢失,如果是烧录、写入的时候检测到坏块,驱动可以帮忙跳过不写入之类的,但这不是一个完整的坏块管理,因为我们还是需要写入成功。

1、page和block的区别

  • flash写的时候一般以page为单位,一个page的大小是2KByte。
  • flash擦除的时候一般以block为单位,一个block为64个page,所以一个block就是0x20000/128KByte。
  • flash坏的时候都是以块为单位,也就是我们说的坏块。

2、新建nmbm分区

需要单独给nmbm一个分区,用来做坏块管理,还有坏块备份。

  • 分区的大小代码里面是根据flash总大小算出一个给nmbm使用的分区大小。
  • 默认是flash总大小的1/16
  • 如果想修改nmbm分区大小,可以修改CONFIG_NMBM_MAX_RATIO和CONFIG_NMBM_MAX_BLOCKS值来调整。

比如我们的flash是128MByte,就是1024个block,会给出(128/16)=8MByte,也就是64个block为nmbm。

所以nmbm的起始block就是1024*(15/16)= 960,从960 block到1024

代码如下:

static bool nmbm_create_new(struct nmbm_instance *ni)
{
    bool success;

    /* Determine the boundary of management blocks */
    ni->mgmt_start_ba = ni->block_count * (NMBM_MGMT_DIV - ni->lower.max_ratio) / NMBM_MGMT_DIV;

    if (ni->lower.max_reserved_blocks && ni->block_count - ni->mgmt_start_ba > ni->lower.max_reserved_blocks)
        ni->mgmt_start_ba = ni->block_count - ni->lower.max_reserved_blocks;

    nlog_info(ni, "NMBM management region starts at block %u [0x%08llx]\n",
          ni->mgmt_start_ba, ba2addr(ni, ni->mgmt_start_ba));
    nmbm_mark_block_color_mgmt(ni, ni->mgmt_start_ba, ni->block_count - 1);
    
    ...
    
}

打印如下:


Initializing NMBM ...
NMBM management region starts at block 960 [0x07800000]

3、nmbm如何如何管理和备份坏块

nmbm会在flash的把flash的最后一段地址,比如64个block做为坏块管理分区,然后这64个block又被分为几个模块。

基础的三个模块:

  • 主信息block:main_table_ba为nmbm分区的第一个block 960
  • 备份信息block:backup_table_ba为nmbm分区的第四个block 963
  • 签名block:signature_ba为nmbm分区的最后一个block 1023

所有的坏块管理内容都会被记录到主信息block里面,内容包括:

  • 整个flash有哪个block是坏的
  • 这个坏的block是否被写入替换了,替换的物理地址在nmbm分区的哪一block
  • nmbm分区还剩余多少个block可以用来替换坏块

如果有坏块,nmbm是如何替换的:

  • 最高替换block:mapping_blocks_top_ba,替换的时候,从nmbm分区的尾部开始替换,也就是1022块开始。比如Bad block 794坏了,此时会使用1022块来替换794块,由nmbm来做映射管理。
  • 最低替换block:mapping_blocks_ba,从1022往前替换,最多只能替换到964这个地址。

4、uboot下支持nmbm功能

打开nmbm功能支持

 # CONFIG_NMBM is not set
 CONFIG_NMBM=y
 # CONFIG_ENABLE_NAND_NMBM is not set
 CONFIG_ENABLE_NAND_NMBM=y
 CONFIG_NMBM_MAX_RATIO=1
 CONFIG_NMBM_MAX_BLOCKS=32

打开nmbm命令支持

 CONFIG_CMD_NMBM=y

修改mtd分区设备为nmbm

 CONFIG_NMBM_MTD=y
 CONFIG_MTDIDS_DEFAULT="nand0=nand0"
 CONFIG_MTDPARTS_DEFAULT="mtdparts=nand0:512k(u-boot),128k(uboot-env),128k(Factory),32768k(firmware),32768k(firmware2)"
 CONFIG_MTDIDS_DEFAULT="nmbm0=nmbm0"
 CONFIG_MTDPARTS_DEFAULT="mtdparts=nmbm0:512k(u-boot),128k(uboot-env),128k(Factory),32768k(firmware),32768k(firmware2)"

Uboot env信息也通过nmbm写入

 CONFIG_ENV_IS_IN_NAND=y
 # CONFIG_ENV_IS_IN_NAND is not set
 CONFIG_ENV_IS_IN_NMBM=y

日志信息

 # CONFIG_NMBM_LOG_LEVEL_DEBUG is not set
 CONFIG_NMBM_LOG_LEVEL_INFO=y
 # CONFIG_NMBM_LOG_LEVEL_WARN is not set
 # CONFIG_NMBM_LOG_LEVEL_ERR is not set
 # CONFIG_NMBM_LOG_LEVEL_EMERG is not set
 # CONFIG_NMBM_LOG_LEVEL_NONE is not set

5、uboot下nmbm信息查看

概况信息查下:

nmbm nmbm0 info   
nmbm0:
Total blocks:                  1024
Data blocks:                   960
Management start block:        960
Info table size:               0x2000
Main info table start block:   960
Backup info table start block: 963
Signature block:               1023
Mapping blocks top address:    1022
Mapping blocks limit address:  964

整个falsh状态查看:

nmbm nmbm0 state
Physical blocks:

Legends:
  -     Good data block
  +     Good management block
  B     Bad block
  I     Main info table
  i     Backup info table
  M     Remapped spare block
  S     Signature block

    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    --------------------------B-------------------------------------
    ----------------------------------------------------------------
    ------------------------------------------B---------------------
    I++i++++++++++++++++++++++++B++++++++++++++++++++++++++++++++MMS```

启动日志打印:

U-Boot SPL 2018.09 (Aug 12 2022 - 01:07:52 +0000)
Trying to boot from NAND

Initializing NMBM ...
NMBM management region starts at block 960 [0x07800000]
Bad block 794 [0x06340000]
Bad block 938 [0x07540000]
Bad block 988 [0x07b80000]
Signature has been written to block 1023 [0x07fe0000]
Main info table has been written to block 960
Backup info table has been written to block 963
Logic block 958 mapped to physical blcok 1022
Logic block 959 mapped to physical blcok 1021
NMBM has been successfully created


U-Boot 2018.09 (Aug 12 2022 - 01:07:52 +0000)

CPU:   MediaTek MT7621AT ver 1, eco 3
Clocks: CPU: 880MHz, DDR: 1200MHz, Bus: 220MHz, XTAL: 40MHz
Model: MediaTek MT7621 reference board (NAND)
DRAM:  128 MiB
NAND:  128 MiB

Initializing NMBM ...
Signature found at block 1023 [0x07fe0000]
First info table with writecount 2 found in block 960
Second info table with writecount 2 found in block 963
NMBM has been successfully attached

Loading Environment from NMBM... OK
In:    uartlite0@1e000c00
Out:   uartlite0@1e000c00
Err:   uartlite0@1e000c00
Net:   
Warning: eth@1e100000 (eth0) using random MAC address - 7e:22:d3:74:d6:0b
eth0: eth@1e100000
DEBUG_UBOOT is OFF
******************************
Software System Reset Occurred
******************************
Saving Environment to NMBM... Erasing on NMBM...
Writing on NMBM... OK
OK

6、内核下支持nmbm功能

驱动配置开启

CONFIG_NMBM=y
# CONFIG_NMBM_LOG_LEVEL_DEBUG is not set
CONFIG_NMBM_LOG_LEVEL_INFO=y
# CONFIG_NMBM_LOG_LEVEL_WARN is not set
# CONFIG_NMBM_LOG_LEVEL_ERR is not set
# CONFIG_NMBM_LOG_LEVEL_EMERG is not set
# CONFIG_NMBM_LOG_LEVEL_NONE is not set
CONFIG_NMBM_MTD=y

dts分区修改:

nmbm {
        compatible = "generic,nmbm";
 
        #address-cells = <1>;
        #size-cells = <1>;
 
        lower-mtd-device = <&nandflash>;
        forced-create;
        max-reserved-blocks = <32>;
 
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;
 
            partition@0 {
                label = "u-boot";
                reg = <0x00000 0x80000>;
                read-only;
            };
            partition@80000 {
                label = "uboot-env";
                reg = <0x80000 0x20000>;
            };
            partition@140000 {
                label = "Factory";
                reg = <0x140000 0x20000>;
            };

            partition@1a0000 {
                label = "firmware";
                reg = <0x1a0000 0x2000000>;
            };
 
            partition@21a0000 {
                label = "firmware2";
                reg = <0x21a0000 0x2000000>;
            };
        };
    };

内核启动的时候也会跑到nmbm检测,如果在uboot已经创建了nmbm的签名块,那内核就不会创建nmbm分区,直接读取主信息block内容就可以。

如果Uboot后升级,那nmbm就没有创建,内核会直接创建nmbm分区。

[    1.187486] mtk-nand 1e003000.nand: Error applying setting, reverse things back
[    1.195312] nand: device found, Manufacturer ID: 0xc2, Chip ID: 0xf1
[    1.201665] nand: Macronix MX30LF1G28AD
[    1.205513] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 128
[    1.213751] Scanning device for bad blocks
[    2.526704] Bad eraseblock 794 at 0x000006340000
[    2.767685] Bad eraseblock 938 at 0x000007540000
[    2.853815] Bad eraseblock 988 at 0x000007b80000
[    2.918621] nmbm nmbm: Signature found at block 1023 [0x07fe0000]
[    2.928248] nmbm nmbm: First info table with writecount 2 found in block 960
[    2.945372] nmbm nmbm: Second info table with writecount 2 found in block 963

mtd分区的检测,如果最后一个分区被其他分区占用(如log),则mtd会主动分割出nmbm使用。

[    2.952510] nmbm nmbm: NMBM has been successfully attached
[    2.958079] 13 ofpart partitions found on MTD device nmbm
[    2.963473] Creating 13 MTD partitions on "nmbm":
[    2.968194] 0x000000000000-0x000000060000 : "u-boot"
[    2.974489] 0x000000060000-0x000000080000 : "uboot-env"
[    3.108509] 0x000000140000-0x000000160000 : "Factory"
[    3.121231] 0x0000001a0000-0x0000021a0000 : "firmware"
[    3.341698] 2 fit-fw partitions found on MTD device firmware
[    3.347396] 0x0000001a0000-0x000000520000 : "kernel"
[    3.353704] 0x000000520000-0x0000021a0000 : "rootfs"
[    3.360171] mtd: device 11 (rootfs) set to be root filesystem
[    3.365994] 0x0000021a0000-0x0000041a0000 : "firmware2"
[    3.385769] 0x000006c00000-0x000008000000 : "log"
[    3.390571] mtd: partition "log" extends beyond the end of device "nmbm" -- size truncated to 0xc00000

7、内核下添加nmbm命令行支持

默认代码内核没办法类似uboot下那也输入命令行查看nmbm信息,可以通过添加最简单的proc文件的方式查看。

将uboot下的查看信息函数简单改造,拷到内核下即可

static int nmbm_state_show(struct seq_file *seq, void *v)
{
    struct nmbm_mtd *nm;
    enum nmmb_block_type bt;
    uint32_t i;

    list_for_each_entry(nm, &nmbm_devs, node) {

        seq_printf(seq, "Physical blocks:\n");
        seq_printf(seq, "\n");

        seq_printf(seq, "Legends:\n");
        seq_printf(seq, "  -     Good data block\n");
        seq_printf(seq, "  +     Good management block\n");
        seq_printf(seq, "  B     Bad block\n");
        seq_printf(seq, "  I     Main info table\n");
        seq_printf(seq, "  i     Backup info table\n");
        seq_printf(seq, "  M     Remapped spare block\n");
        seq_printf(seq, "  S     Signature block\n");
        seq_printf(seq, "\n");

        for (i = 0; i < nm->ni->block_count; i++) {
            if (i % 64 == 0)
                seq_printf(seq, "    ");

            bt = nmbm_debug_get_phys_block_type(nm->ni, i);
            if (bt < __NMBM_BLOCK_TYPE_MAX)
                seq_printf(seq, "%c", nmbm_block_legends[bt]);
            else
                seq_printf(seq, "?");

            if (i % 64 == 63)
                seq_printf(seq, "\n");
        }

        seq_printf(seq, "\n");
        seq_printf(seq, "Logical blocks:\n");
        seq_printf(seq, "\n");

        seq_printf(seq, "Legends:\n");
        seq_printf(seq, "  -     Good block\n");
        seq_printf(seq, "  +     Initially remapped block\n");
        seq_printf(seq, "  M     Remapped block\n");
        seq_printf(seq, "  B     Bad/Unmapped block\n");
        seq_printf(seq, "\n");

        for (i = 0; i < nm->ni->data_block_count; i++) {
            if (i % 64 == 0)
                seq_printf(seq, "    ");

            if (nm->ni->block_mapping[i] < 0)
                seq_printf(seq, "B");
            else if (nm->ni->block_mapping[i] == i)
                seq_printf(seq, "-");
            else if (nm->ni->block_mapping[i] < nm->ni->data_block_count)
                seq_printf(seq, "+");
            else if (nm->ni->block_mapping[i] > nm->ni->mapping_blocks_top_ba &&
                nm->ni->block_mapping[i] < nm->ni->signature_ba)
                seq_printf(seq, "M");
            else
                seq_printf(seq, "?");

            if (i % 64 == 63)
                seq_printf(seq, "\n");
        }
        seq_printf(seq, "\n");
    }
    return 0;
}

static int nmbm_state_open(struct inode *inode, struct file *file)
{
    return single_open(file, nmbm_state_show, PDE_DATA(inode));
}

static const struct file_operations nmbm_state_fops = {
    .owner   = THIS_MODULE,
    .open    = nmbm_state_open,
    .read    = seq_read,
    .llseek  = seq_lseek,
    .release = single_release,
};

之后就可以通过命令行查看

root@openwrt:~# cat /proc/nmbm_state 
Physical blocks:

Legends:
  -     Good data block
  +     Good management block
  B     Bad block
  I     Main info table
  i     Backup info table
  M     Remapped spare block
  S     Signature block

    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    ----------------------------------------------------------------
    --------------------------B-------------------------------------
    ----------------------------------------------------------------
    ------------------------------------------B---------------------
    ----------------------------B---I++i++++++++++++++++++++++++MMMS

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容