MTD坏块管理(二)-内核获取Nandflash的参数过程

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中被定义。


你可能感兴趣的:(MTD坏块管理(二)-内核获取Nandflash的参数过程)