Linux mtd子系统专栏分析之四 NANDFLASH驱动模型概述

      在上几篇文章中,基本上理清了mtd子系统的架构,并将mtd子系统对上的抽象及相应的函数接口进行了说明。从本章开始,主要以nandflash为例,介绍具体类型的闪存设备驱动模型是如何衔接mtd的抽象层,并完成对闪存芯片的读写操作。

 

 

nandflash概念

    针对一个nandflash,包括块、页;一个flash包含多个块;而一个块又包含多个页。针对每一个页而言,又包含对应的spare area,主要用于存储数据校验信息(即ecc信息),用于纠错;也存储坏块标志(一个块中仅有一个页对应oob存储坏块标志)。而针对文件系统而言,具体到yaffs2文件系统,也会将其文件系统的组织信息信息存储到oob中。

 

nandlfash及nand controller的特点

针对nandflash,我们需要从nandflash自身特性关注以下几点:

  1. nandflash存在bit翻转的情况,因此需要相应的纠错算法,而纠错与检测操作由具体的nandflash controller实现,可以实现硬件纠错(如汉明纠错、bch4、bch8纠错算法等),也可使用软件纠错算法;
  2. Nandflash controller与nandflash之间通信命令是统一的,即针对一个nandflash controller可以与任意一个nandflash通信;
  3. 针对每一个nandflash controller,访问该nandflash controller的方式有所不同,如寄存器定义、读写地址等有所不同;
  4. nandflash的擦除次数由显示(10万次),因此在使用过程中,存在坏块

 

 

 

 

Linux nandflash驱动模块抽象

而针对nandflash驱动模块而言,基本上也就是按照上面的特点进行抽象,其驱动模型大概可分为如下几部分:

  1. 针对每一个nandflash controller,抽象结构体变量struct nand_chip;所有的接口以及变量均由该结构体去实现关联
  2. 基于nandflash controller与nandflash的通信命令是统一的,抽象出统一的读、写、擦除等接口,作为mtd_info的_write、_read、badblock等接口;
  3. 基于nandflash存在bit翻转且每一个nandcontroller实现的纠错算法不同,因此每一个nandflash controler需要实现自己的纠错接口、校验接口等;
  4. 针对每一个nandflash controller而言,需要提供访问该nandflash controller的接口(包括向nandflash发送命令的接口、读写数据接口(通过nandflash controller,间接实现访问nandflash))。

 

       在驱动模块中,主要抽象了nand_chip结构体,以及对mtd层而抽象出来的统一的处理接口。下面是nand_chip结构体、对应的抽象接口以及mtd_info之间的关联关系图。下面我们来具体说明它们的关联,并与nandflash驱动模块进行关联说明。

  1. mtd_info->priv指向nand_chip,实现mtd与nand flash驱动模块的关联;
  2. nandflash驱动模型对上抽象出统一的接口,用于抽象针对nandflash的操作(与vfs接口抽象、mtd模块向上抽象统一读写接口类似),并赋值给mtd_info中对应的函数指针(即mtd_info的_erase、_write、_read等),为nand_write、nand_read、nand_read_oob等等,此处的读写数据接口,可读取任意长度的数据。
  3. 因nandflash存在纠错、校验等因此nandflash驱动模块又抽象针对ecc的结构体struct nand_ecc_ctrl,而该结构体中定义了读写一页数据的接口(针对nandflash而言,读写的单位为页,而擦除的单位为块大小),而不同的nandflash控制器,其支持的校验及纠错方式有所不同,因此这部分接口需要各nandflash控制器驱动实现。
  4. Nand_chip本身也提供了操作nandflash的接口,包括read_byte、read_buf、write_buf、block_bad等接口,这部分接口相对nand_ecc_ctrl的接口而言更加底层,实现一个字节或者多个字节的读写,同时也提供nand_chip芯片选择等接口以及命令控制相关的接口等。而这部分接口也是和nand_controller所息息相关的,因此也有相应的nand_controller驱动实现(当然若nand_controller没有特殊的操作,则可以使用nandflash模块已定义的通用接口)

通过以上几步即完成了mtd、nand_chip的关联,同时也就完成了mtd_write、mtd_read接口通过nand_write、mtd_read接口,然后再到nand_ecc_ctrl->read_page/write_page接口,最终调用nand_chip->read_buf/write_buf,实现与nandflash的读写通信。

 

 

Nandflash驱动模块相关的数据结构

        针对nandflash驱动模块,刚才我们已经大致说明了几个数据结构nand_chip、nand_ecc_ctrl,下面我们详细说明下nandflash驱动模块相关的数据结构。针对linux内核各子模块而言,理解了其数据结构抽象,基本上也就对模块实现理解了60%左右,因此针对linux内核各模块的学习,强烈建议好好理解其相应的数据结构及它们之间的关联。nandflash驱动模块的结构体包括nand_chip、nand_onfi_params、nand_hw_control、nand_ecclayout、nand_ecc_ctrl、nand_hw_control、nand_bbt_descr等,这些结构体以nand_chip为主。下面我们逐一说明

nand_chip

该结构体定义了nand_controller的属性以及接口,主要包括:

  1. 与nand_controller通信的地址空间(包括命令下发、读写操作的接口,即IO_ADDR_R/IO_ADDR_W);
  2. 通过nand_controller读写flash数据的接口(read_byte、read_word、write_buff、read_buff,芯片选择接口select_chip、坏块判断及坏块标记接口block_bad、block_markbad,向nandflash发送命令的接口cmd_ctrl、cmdfunc、waitfunc、erase_cmd,坏块表相关的接口scan_btt等、支持onfi规范的nandflash相关的操作接口及属性等);
  3. 芯片的个数、芯片的总大小、页大小、block大小、坏块标记在oob的位置及个数等
  4. oob中ecc位置及大小相关的结构体变量nand_ecclayout
  5. ecc纠错相关的接口及属性的结构体变量nand_ecc_ctrl。

 

 

nand_ecc_ctrl

该结构体变量的定义如下,主要定义了一个nand_controller所支持的ecc计算、校验及纠错相关的内容:

  1. 定义了ecc类型(无、软件ecc、硬件ecc等);
  2. 定义了一个page需要进行ecc计算的次数,每次ecc计算对应的数据大小(如每512字节进行一次ecc计算),每次ecc计算所产生的ecc字节数等等;
  3. 定义了ecc操作相关的接口(若开启ecc接口hwctl、计算ecc值接口calculate、纠错接口correct(主要用于读取数据时,若读取数据计算的ecc值与存储在oob中的ecc不匹配,则需要纠错,如bch8纠错算法,则每512字节可最多发现9bit错误,最大纠正8bit数据等),并提供了读写一页数据的接口,主要供mtd_info->_read/_write调用,即被nand_read、nand_write调用,还包括读写oob数据的接口,在之前我们说明oob主要存储ecc信息,但针对yaffs2文件系统,也存储文件系统相关的信息,因此针对挂载yaffs2文件系统而言,要在boot和kernel中确认好yaffs2文件系统信息存储在oob中的起始位置与大小,并保持一致)

 

 

nand_ecclayout

     该结构体主要用于说明ecc值在oob中存储的位置及大小,在每一个nand_controller的驱动中,会定义不同page size对应的nand_ecclayout,用于指明该page size对应的oob中的ecc的位置信息及大小等。

  1. eccbytes表明了ecc数据的大小,这个针对选择的不同的纠错算法有所不同,比如bch4和bch8相比,每512字节所产生的ecc数据大小则是不同的(bch8产生的ecc大概为13bytes@per512bytes)。
  2. eccpos则用于说明每一个ecc对应的位置;
  3. oobavail则说明该oob除去ecc字节,所剩余的可用字节;
  4. oobfree则用于说明3中剩余可用字节的位置。

 

        该结构体变量是一个非常重要的变量,需要保证bootloader和kernel中定义大小及pos是完全相同的,否则则可能导致系统无法在kernel中使用。另外,若使用yaffs2文件系统,则在进行nandflash芯片选型时,需要确认nandflash的oob在存储完ecc后有足够的空间存储yaffs2文件系统相关数据的空间(虽然也可以将yaffs2文件系统相关的信息存储page中,但那样会导致系统的读写时间变慢)。

nand_hw_control

        该结构体变量主要定义了锁、等待队列,主要用于nandflash操作临界问题的解决,如当一个nandcontroller处于读操作时,若系统又触发了针对该nandcontroller的写操作,则将该写操作放入等待队列中,当读操作完成后唤醒该等待队列实现写操作。

struct nand_hw_control {

spinlock_t lock;

struct nand_chip *active;

wait_queue_head_t wq;

};

 

       nand_bbt_descr与nand_onfi_params主要用于坏块表和onfi规范的nandflash,针对坏块表,我之前没有使用过,个人感觉可以不使用坏块表,即使使用坏块表,也就使用内存坏块表即可,也没有必要在nandflash中预留一些块用于存储坏块表(个人感觉)。而nand_onfi_params主要用于支持onfi规范的nandflash,此处也不再介绍。

 

         以上即为本篇文章的内容,主要介绍了nand_chip的抽象说明以及接口间的关联,并说明了nandflash驱动模块相关的结构体变量。下一篇文章主要说明相应的操作接口,以及nandcontroller驱动的初始化过程等内容。

发布了151 篇原创文章 · 获赞 34 · 访问量 46万+

猜你喜欢

转载自blog.csdn.net/lickylin/article/details/105151285
今日推荐