MTD坏块管理机制中,起着核心作用的数据结构是nand_chip,在此以TCC8900-Linux中MTD的坏块管理为例作一次介绍。
MTD在Linux内核中同样以模块的形式被启用,TCC_MTD_IO_Init()函数完成了nand_chip初始化、mtd_info初始注册,
坏块表的管理机制建立等工作。
nand_chip在TCC_MTD_IO_Init函数中的实例名称是this,mtd_info 的实例名称为TCC_mtd,这里有一个比较巧妙的处理方法:
TCC_mtd=kmalloc(sizeof(struct mtd_info)+sizeof(struct nand_chip),GFP_KERNEL);
this=(struct nand_chip*)(&TCC_mtd[1]);
在以后的操作中,只需得知TCC_mtd即可找到对应的nan_chip实例。
获得必要的信息后(包括nand_chip方法的绑定),流程进入nand_scan(TCC_mtd,1).
nand_scan(struct mdt_info *mtd, int maxchips);
调用nand_scan_ident(mtd,maxchips)和nand_scan_tail(mtd);
nand_scan_ident(...)调用了一个很重要的函数:nand_get_flash_type(...)
*从nand_get_flash_type(...)函数中可以看出每个nandflash前几个字节所代表的意思都是约定好了的:
第一个字节:制造商ID
第二个字节:设备ID
第三个字节:MLC 数据
第四个字节:extid (比较总要)
其中设备ID是访问nand_flash_ids表的参照,该表在drivers/mtd/nand/nand_ids.c中定义
Linux内核在nand_flash_ids参照表中,通过匹配上述设备ID来查找nandflash的详细信息,
nand_flash_ids中的举例如下:
struct nand_flash_dev nand_flash_ids[]={
......
{"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
{"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
{"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
{"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
......
}
466 struct nand_flash_dev {
467 char *name;
468 int id;
469 unsigned long pagesize;
470 unsigned long chipsize;
471 unsigned long erasesize;
472 unsigned long options;
473 };
值得一提的是,MTD子系统会把从nand_flash_ids表中找到的chipsize复制给mtd->size,这在有些应用中显得不合适,
在有些方案中,并不是把nandflash的所有存储空间都划分为MTD分区,Telechips的TCC89XX方案就是这样,4G的nandflash
上,可以划分任意大小的MTD分区,错误的mtd->size的后果非常严重,造成系统启动慢,整个MTD的坏块管理机制瘫痪等等。
随后,nand_get_flash_type通过extid计算出了以下信息:
mtd可写区大小:mtd->writesize=1024<<(extid&0x03);
这里可以看成1024*(1*2的(extid&0x03)次方),
mtdoob区大小:extid>>=2;mtd->oobsize = (8<<(extid&0x1))*(mtd->writesize>>9);
每512字节对应(8*2的(extid&0x1)次方)字节oob数据
mtd擦写块大小:extid>>=2;mtd->erasesize=(64*1024)<<(extid&0x03);
nand数据宽度 :extid>>=2;busw=(extid&0x01)?NAND_BUSEWIDTH_16:0; 现在大多为8位数据宽度
可以看出第四个字节extid的意义:
高|0 | 0 | 00 | 0 | 0 | 00 |低
|无用|数据宽度|擦写块算阶|无用|oob算阶| 可写区算阶|
nand_get_flash_type(...)还确立了nandflash中的坏块标记在oob信息中的位置:
if(mtd->writesize>512||(busw&NAND_BUSWIDTH_16))
chip->badblockpos = NAND_LARGE_BADBLOCKS_POS;//大页面flash的坏块信息存储地址为oob信息中的第1个字节开始处
else
chip->badblockpos = NAND_SMALL_BADBLOCKS_POS;//大页面flash的坏块信息存储地址为oob信息中的第6个字节开始处
对于Samsun和Hynix的MLC型nandflash,坏块标记所在的页是每块的最后一个页,而Samsung,Hynix,和AMD的SLC型nandflash
中,坏块标记分别保存在每块开始的第1,2个页中,其他型号的nandflash大多都保存在第一个也中,为此需要作下标记:
坏块标记保存在块的最后一页中:chip->options |= NAND_BBT_SCANLASTPAGE;
坏块标记保存在块的第1,2页中 :chip->options |= NAND_BBT_SCAN2NDPAGE;
nand_scan之后调用nand_scan_tail(mtd)函数,
nand_scan_tail(...)函数主要完成MTD实例中各种方法的绑定,例如:
3338 mtd->read = nand_read;
3339 mtd->write = nand_write;
3340 mtd->panic_write = panic_nand_write;
3341 mtd->read_oob = nand_read_oob;
3342 mtd->write_oob = nand_write_oob;
3343 mtd->sync = nand_sync;
nand_scan_tail(...)调用chip->scan_bbt()完成坏块表的有关操作。
chip->scan_bbt的绑定过程是在nand_scan_ident()->nand_set_defaults():chip->scan_bbt = nand_default_bbt.
即真正用于坏块操作的是nand_default_bbt函数,该函数在nand_bbt.c中被定义。