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

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值