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```

啟動日志打?。?/p>

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閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容