zoukankan      html  css  js  c++  java
  • Linux MTD介绍

    1. 介绍

    MTD,即Memory Technology Device,值得是内存技术设备

    字符设备和块设备的区别在于前者只能被顺序读写,后者可以随机访问;同时,两者读写数据的基本单元不同

    字符设备: 以字节为基本单位,在Linux中,字符设备实现的比较简单,不需要缓冲区即可直接读写,内核例程和用户态API一一对应,用户层的Read函数直接对应了内核中的Read例程,这种映射关系由字符设备的file_operations维护
    块设备: 以块为单位接受输入和返回输出,对这种设备的读写是按块进行的,其接口相对于字符设备复杂,没有直接到块设备层,而是直接到文件系统层,然后再由文件系统层发起读写请求

    由于块设备的I/O性能与CPU相比很差,因此,块设备的数据流往往会引入文件系统的cache机制

    注意:MTD设备既非块设备也不是字符设备,但可以同时提供字符设备和块设备接口来操作

    2. 概述

    Linux中MTD的所有源码位于/drivers/mtd子目录下

    MTD设备通常可分为四层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层

    硬件驱动层负责在init时驱动Flash硬件并建立从具体设备到MTD原始设备映射关系
    TIP: 映射关系通常包括 分区信息、I/O映射及特定函数的映射

    drivers/mtd/chips : CFI/JEDEC接口通用驱动
    drivers/mtd/nand : NAND通用驱动和部分底层驱动程序
    drivers/mtd/maps : NOR Flash映射关系相关函数
    drivers/mtd/devices : NOR Flash底层驱动

    MTD原始设备,用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。
    mtdcore.c : MTD原始设备接口相关实现
    mtdpart.c : MTD分区接口相关实现

    MTD设备层,基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。
    mtdchar.c : MTD字符设备接口相关实现
    mtdblock.c : MTD块设备接口相关实现

    设备节点,通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)和MTD字符设备节点(主设备号为90)
    通过访问此设备节点即可访问MTD字符设备和块设备

    3. 数据结构

    MTD重要的数据结构包括mtd_info、mtd_part、mtd_partition、map_info、nand_chip、nand_ecclayout
    mtd_info表示mtd原始设备, 所有mtd_info结构体被存放在mtd_info数组mtd_table中

    成员 作用
    type mtd类型, 包括MTD_NORFLASH,MTD_NANDFLASH等(See mtd-abi.h)
    flags 标志位, MTD_WRITEABLE,MTD_NO_ERASE等(See mtd-abi.h)
    size mtd设备的大小
    erasesize 主要的擦除大小, 即Flash的块大小 (tip: mtd设备可能有多个erasesize)
    writesize 写大小, 对于norFlash是字节,对nandFlash为一页
    oobsize 每块oob数据量, eg 16
    oobavail  
    name 命名
    index  
    ecclayout nand_ecclayout结构体指针, 表示的是ecc布局,可参考硬件手册的OOB中ecc布局
    numeraseregions 可变擦除区域的数目, 通常为1
    eraseregions mtd_erase_region_info结构体指针, 可变擦除区域
    erase 擦除Flash函数
    read/write 读写Flash函数
    read_oob/write_oob 带oob读写Flash函数
    suspend/resume Power Management functions
    priv 私有数据, cfi接口flash指向map_info结构, 或指向自定义flash相关结构体

    mtd_part表示MTD分区,其中包含了mtd_info,每一个分区都是被看成一个MTD原始设备

    成员 作用
    mtd 分区信息, 大部分由master决定
    master 分区的主分区
    offset 分区的偏移地址
    index 分区号 (3.0后不存在该字段)
    list 将mtd_part链成一个链表mtd_partitons

    mtd_partition的主要数据结构

    成员 作用
    name  
    size  
    offset  
    mask_flags  
    ecclayout  
    mtdp  

    map_info的主要数据结构

    成员 作用
    name 名称
    size 大小
    phys 物理地址
    bankwidth 总线宽度(in octets)
    virt 虚拟地址,通常通过ioremap将物理地址进行映射得到
    read/copy_from/write/copy_to 读写函数
    map_priv_1/map_priv_2 驱动可用的私有数据

    nand_chip的主要数据结构

    成员 作用
    IO_ADDR_R/IO_ADDR_W 读/写8根io线的地址
    read_byte/read_word 从芯片读一个字节/字
    read_buf/write_buf 读芯片读取内容至缓冲区/将缓冲区内容写入芯片
    verify_buf  
    select_chip  
    block_bad 检查是否坏块
    block_markbad 标识坏块
    cmd_ctrl 硬件相关控制函数
    init_size  
    dev_ready  
    cmdfunc 命令处理函数
    waitfunc  
    erase_cmd 擦除命令
    scan_bbt 扫描坏块
    errstat  
    write_page  
    options 与具体的NAND 芯片相关的选项, 如NAND_USE_FLASH_BBT等(nand.h)
    page_shift  
    ecclayout nand_ecclayout类型结构体, ECC布局信息
    ecc nand_ecc_ctrl类型结构体, ECC控制结构

    nand_ecclayout的主要数据结构

    成员 作用
    eccbytes ecc的字节数(For 512B-per-page, eccbytes is 3)
    eccpos ecc数据在oob中的位置
    oobavail oob中可用的字节数, MTD 会根据其它三个变量自动计算得到
    oobfree nand_oobfree类型结构体, 显示定义空闲的oob 字节

    4. MTD相关层实现

    4.1 MTD设备层

    mtd字符设备接口:
    mtdchar.c 实现了字符设备接口,通过它,用户可以直接操作Flash 设备。
    Ø 通过read()、write()系统调用可以读写Flash。
    Ø 通过一系列IOCTL 命令可以获取Flash 设备信息、擦除Flash、读写NAND 的OOB、获取OOB layout 及检查NAND 坏块等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL)
    TIP: mtd_read和mtd_write直接直接调用mtd_info的read 函数,因此,字符设备接口跳过patition这一层

    mtd块设备接口:
    主要原理是将Flash的erase block中的数据在内存中建立映射,然后对其进行修改,最后擦除Flash 上的block,将内存中的映射块写入Flash 块。整个过程被称为read/modify/erase/rewrite 周期。
    但是,这样做是不安全的,当下列操作序列发生时,read/modify/erase/poweroff,就会丢失这个block 块的数据。
    块设备模拟驱动按照block 号和偏移量来定位文件,因此在Flash 上除了文件数据,基本没有额外的控制数据。

    4.2 MTD原始设备层

    MTD原始设备层

    4.3 硬件驱动层

    4.3.1 NOR Flash驱动结构

    Linux系统实现了针对cfi,jedec等接口的通用NOR Flash驱动
    在上述接口驱动基础上,芯片级驱动较简单
         定义具体内存映射结构体map_info,然后通过接口类型后调用do_map_probe() 
    以h720x-flash.c为例(位于drivers/mtd/maps)
    - 定义map_info结构体, 初始化成员name, size, phys, bankwidth
    - 通过ioremap映射成员virt(虚拟内存地址)
    - 通过函数simple_map_init初始化map_info成员函数read,write,copy_from,copy_to
    - 调用do_map_probe进行cfi接口探测, 返回mtd_info结构体
    - 通过parse_mtd_partitions, add_mtd_partitions注册mtd原始设备

    4.3.2 NAND Flash驱动结构

    Linux实现了通用NAND驱动(drivers/mtd/nand/nand_base.c)
    tip: For more, check 内核中的NAND代码布局 
    芯片级驱动需要实现nand_chip结构体
    MTD使用nand_chip来表示一个NAND FLASH芯片, 该结构体包含了关于Nand Flash的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制。
    Ø NAND芯片级初始化
    主要有以下几个步骤:
    - 分配nand_chip内存,根据目标板及NAND控制器初始化nand_chip中成员函数(若未初始化则使用nand_base.c中的默认函数),将mtd_info中的priv指向nand_chip(或板相关私有结构),设置ecc模式及处理函数
    - 以mtd_info为参数调用nand_scan()探测NAND FLash。
       nand_scan()会读取nand芯片ID,并根据mtd->priv即nand_chip中成员初始化mtd_info
    - 若有分区,则以mtd_info和mtd_partition为参数调用add_mtd_partitions()添加分区信息
    -

    Ø MTD对NAND芯片的读写
    主要分三部分:
    A、struct mtd_info中的读写函数,如read,write_oob等,这是MTD原始设备层与FLASH硬件层之间的接口;
    B、struct nand_ecc_ctrl中的读写函数,如read_page_raw,write_page等,主要用来做一些与ecc有关的操作;
    C、struct nand_chip中的读写函数,如read_buf,cmdfunc等,与具体的NAND controller相关,就是这部分函数与硬件交互,通常需要我们自己来实现。
    tip: nand_chip中的读写函数虽然与具体的NAND controller相关,但是MTD也为我们提供了默认的读写函数,如果NAND controller比较通用(使用PIO模式),那么对NAND芯片的读写与MTD提供的这些函数一致,就不必自己实现这些函数。

    上面三部分读写函数相互配合完成对NAND芯片的读写
    首先,MTD上层需要读写NAND芯片时,会调用struct mtd_info中的读写函数,接着struct mtd_info中的读写函数就会调用struct nand_chip或struct nand_ecc_ctrl中的读写函数,最后,若调用的是struct nand_ecc_ctrl中的读写函数,那么它又会接着调用struct nand_chip中的读写函数。
    eg:  以读为例
    MTD上层会调用struct mtd_info中的读page函数,即nand_read函数。
    接着nand_read函数会调用struct nand_chip中cmdfunc函数,这个cmdfunc函数与具体的NAND controller相关,它的作用是使NAND controller向NAND 芯片发出读命令,NAND芯片收到命令后,就会做好准备等待NAND controller下一步的读取。
    接着nand_read函数又会调用struct nand_ecc_ctrl中的read_page函数,而read_page函数又会调用struct nand_chip中read_buf函数,从而真正把NAND芯片中的数据读取到buffer中(所以这个read_buf的意思其实应该是read into buffer,另外,这个buffer是struct mtd_info中的nand_read函数传下来的)。
    read_buf函数返回后,read_page函数就会对buffer中的数据做一些处理,比如校验ecc,以及若数据有错,就根据ecc对数据修正之类的,最后read_page函数返回到nand_read函数中。
    对NAND芯片的其它操作,如写,擦除等,都与读操作类似

    4.3.3 Flash转换层

    Tranlation Layer
    逻辑块地址(Logical Block Address)对应到Flash存储器的物理位置,使系统能把Flash当作普通的硬盘一样处理

    FTL主要用于NOR Flash;NFTL用于NAND Flash

    闪存转换层要做下面的操作来完成写请求:
    - 将这个扇区所在擦除块的数据读到内存中,放在缓存中
    - 将缓存中与这个扇区对应的内容用新的内容替换。
    - 对该擦除块执行擦除操作。   
    - 将缓冲中的数据写回该擦除块。

    参考:
    <MTD Subsystem for Linux>

  • 相关阅读:
    OSX安装nginx和rtmp模块(rtmp直播服务器搭建)
    用runtime来重写Coder和deCode方法 归档解档的时候使用
    Homebrew安装卸载
    Cannot create a new pixel buffer adaptor with an asset writer input that has already started writing'
    OSX下面用ffmpeg抓取桌面以及摄像头推流进行直播
    让nginx支持HLS
    iOS 字典转json字符串
    iOS 七牛多张图片上传
    iOS9UICollectionView自定义布局modifying attributes returned by UICollectionViewFlowLayout without copying them
    Xcode6 iOS7模拟器和Xcode7 iOS8模拟器离线下载
  • 原文地址:https://www.cnblogs.com/hzl6255/p/2824043.html
Copyright © 2011-2022 走看看