Linux MMC驱动架构浅析

Linux MMC驱动架构浅析

MMC驱动模型

Linux内核设计了MMC子系统,用于管理MMC/SD等设备,MMC/SD存储设备是一种典型的块设备。MMC子系统的框架结构如下图所示。

块设备(MMC_BLOCK)
块设备的相关驱动,即实现块设备的驱动程序,负责驱动MMC core抽象出来的虚拟的card设备,并对接内核其它的framework(例如块设备、TTY、wifi)等实现具体的功能。如MMC/SD卡设备驱动按照 linux块设备驱动程序的框架实现一个MMC/SD卡的块设备驱动,在 block.c 当中我们可以看到写一个块设备驱动程序时需要的 block_device_operations 结构体变量的定义,其中有 open/release/request 函数的实现,而 queue.c 则是对内核提供的请求队列的封装。

核心层(CORE)
整个MMC的核心层,这部分是不同协议和规范的实现,为MMC控制器(host)层和块设备(card)驱动层提供接口函数。核心层封装了 MMC/SD 卡的命令(CMD),例如存储卡的识别、设置、读写、识别、设置等命令。core.c 文件是由 sd.c 、 mmc.c 两个文件支撑的, core.c 把 MMC 卡、 SD 卡的共性抽象出来,它们的差别由 sd.c 和 sd_ops.c 、 mmc.c 和 mmc_ops.c 来完成。

控制器层(host)
主机端MMC控制器的驱动,主机控制器则是依赖于平台。针对不同芯片,实现控制器对应的驱动代码。例如中断函数注册,控制器寄存器初始化等等。然后它会向 核心(core)层注册一个主机( host ),用结构 mmc_host_ops 描述,这样核心层就可以拿着这个 host 来操作对应的卡控制器,对核心(core)层是不透明的。

Linux MMC驱动架构浅析_第1张图片
MMC核心(CORE)
MMC协议是一个总线协议,因此包括Host controller、Bus、Card三类实体。相应的,MMC framework抽象出了host、bus、card三个软件实体,以便和硬件一一对应。

Host:负责驱动Host controller,提供诸如访问card的寄存器、检测card的插拔、读写card等操作方法。从设备模型的角度看,host会检测卡的插入,并向bus注册MMC card设备。

Bus:是MMC bus的虚拟抽象,以标准设备模型的方式,收纳MMC card(device)以及对应的MMC driver(driver);

Card:抽象具体的MMC卡,由对应的MMC driver驱动(从这个角度看,可以忽略MMC的技术细节,只需关心一个个具有特定功能的卡设备,如存储卡、WIFI卡、GPS卡等等)。

Linux MMC驱动架构浅析_第2张图片
块设备层(MMC_BLOCK)
块设备针对不同客户端的设备驱动程序。如SD卡、T-flash卡、SDIO接口的GPS和wi-fi等设备驱动。

Linux MMC驱动架构浅析_第3张图片

驱动模形数据结构

mmc_host:表示一个MMC控制器
Linux MMC驱动架构浅析_第4张图片

mmc_card:MMC设备描述

Linux MMC驱动架构浅析_第5张图片
mmc_driver:MMC操作函数

Linux MMC驱动架构浅析_第6张图片

MMC 模块总线模型

mmc子系统涉及到三条总线:
platform_bus_type:
host设备被封装成platform_device注册到Linux驱动模型中,Host驱动相应的driver和device挂载在Linux内核内置的虚拟抽象总线platform_bus_type。两者的匹配采用名称匹配的方式,即driver和device两者的name一样则认为该device对应该driver
mmc_bus_type:
Card驱动相应的driver和device挂载在mmc自己创建的虚拟总线mmc_bus_type下,直接匹配。
sdio_bus_type:
Sdio驱动相应的driver和device挂载在mmc自己创建的虚拟总线sdio_bus_type下,ID匹配。

瑞芯微MMC总线、驱动、设备框图

Linux MMC驱动架构浅析_第7张图片

瑞芯微MMC设备源码流程分析

Linux MMC驱动架构浅析_第8张图片

瑞芯微MMC驱动源码分析

概述

从上面总线设备驱动之间的关系图以及流程图可知,设备启动时,首先调用subsys_initcall向linux系统注册了mmc_bus和sdio_bus两条总线,用来管理块设备和sdio接口类型的设备。接着调用module_init向系统注册了一条mmc_rpmb_bus总线、一个mmc块设备和MMC driver。最后调用module_platform_driver,把mmc controler注册到platform总线,同时扫描一次挂载到mmc控制器上的设备。

这里有几个重要的对象,即mmc_host、mmc_card、mmc driver。针对mmc controller,该子系统抽象为mmc_host,用于描述一个mmc 控制器;针对mmc、sd、tf卡等,该子系统抽象为mmc_card,用于描述卡信息;针对通信总线,抽象出mmc_bus;针对mmc、sd、tf,mmc子系统完成了统一的mmc driver,针对mmc总线规范以及SD规范,其已经详细的定义了一个存储卡的通信方式、通信命令,因此LINUXmmc子系统定义了mmc driver,用于和mmc、sd、tf等卡的通信,而不需要驱动开发人员来开发卡驱动。

从上面的图中看到,在mmc总线模型中只注册了一个mmc driver,该驱动适配所有的mmc card。一个mmc host与一个mmc card绑定。Mmc card属于热插拔的设备,而mmc card的创建主要由mmc host负责探测与创建,mmc host根据卡在位检测引脚,当检测到mmc card的存在后,即创建mmc card,同时注册至mmc bus上,并完成与mmc driver的绑定操作。
因mmc_card一般均是存储设备,因此针对该设备的访问即需要借助LINUX内核的块设备模型,因此mmc子系统也必须要实现块设备驱动,借助该块设备驱动模型,将mmc card与vfs完成了关联,即可通过系统调用借助VFS模型实现对块设备的读写访问操作。

sdio总线驱动模型和mmc类型,结构体上的区别为其driver类型为sdio_driver,并增加了sdio_func结构体变量(该结构体包含了该sdio设备相关的厂商id、设备id,同时包含了mmc_card),与mmc总线驱动模型的区别为:因sdio主要突出接口概念,其设备端可以连接wifi、gps等设备,因此其外设备驱动需要由驱动工程师自己实现,sdio驱动模块不提供对应的驱动。

MMC bus的定义及其接口分析

MMC bus数据结构

Linux MMC驱动架构浅析_第9张图片
mmc_dev_groups : 定义了dev_attrs属性,针对所有注册到mmc bus上的设备,均会创建mmc_dev_attrs中定义的属性文件
mmc_bus_match :match接口用于实现mmc card与mmc driver的匹配检测,(始终返回1)
mmc_bus_uevent :uevent接口主要用于添加该mmc bus的uevent参数(在调用device_add时,会调用kobject_uevent向应用层发送设备添加相关的事件(通过netlink 发送和 call_usermodehelper机制(向/proc/sys/kernel/hotplug中写入usermodehelper机制调用的应用层程序)),而kobject_uevent会调用该device所属bus和class的uevent接口,添加需要发送到应用的event参数);

mmc_bus_probe :probe接口主要用于mmc card与mmc driver匹配成功后,调用该mmc bus的probe接口实现探测操作

mmc_bus_pm_ops :pm是电源管理相关的接口
mmc_dev_attrs:该属性为所有注册至该总线上的设备所默认创建的,其定义如下,主要提供只读的设备属性,该属性用于提供mmc card的类型,在具体的mmc card目录下(sysfs),会创建type的文件,该文件只读,读取该文件可以获取mmc card的类型,目前支持的类型包括mmc、sd、sdio、sd combo。

mmc_bus_match:该接口主要用于mmc card、mmc driver的匹配检测, mmc bus的mmc driver由mmc 子系统实现,且针对mmc/sd/emmc等存储卡设备,其均与mmc子系统实现的mmc driver匹配,因此此处的mmc_bus_match并没有进行匹配检测,直接返回1,表示mmc 子系统实现的mmc driver可匹配所有注册至mmc bus上的mmc card。
mmc_bus_probe/mmc_bus_remove:这两个接口均直接调用mmc 子系统注册的mmc driver的probe/remove接口,实现简单。

mmc_bus_uevent:该接口主要是提供mmc bus添加的event env,该接口主要提供“MMC_TYPE”、“MMC_NAME”、“MODALIAS”这三个env。若应用层的udev、mdev需要关注mmc card的这三个env,则可以添加对应这三个env的规则即可。
因mmc driver仅有一个,因此针对mmc bus而言其match函数直接返回1,而不需要像spi/i2c总线的match接口那样对设备和驱动进行匹配检测;

因一个mmc控制器仅与一个mmc card关联,且mmc子系统提供了mmc rescan接口,可以实现对mmc host下的mmc card进行扫描并进行mmc card的创建、与mmc host的绑定以及注册至mmc总线上;因此不需要像上述2中所述的i2c/spi那样,将所有已注册的控制器设备链接在一起方便查找从而实现i2c/spi设备的注册与绑定;
因mmc/emmc协议规范已经规定了访问mmc card的命令格式以及相应的寄存器定义,所有mmc/sd/tf/emmc设备均需要遵守,因此mmc子系统针对访问mmc card的命令抽象出统一的接口,包括设备状态设置、卡使能去使能、sleep/awake、poweroff notify、cid/rca/dsr/csd寄存器读写、通过mmc switch命令实现与extend csd寄存器的读写等接口

续待......

你可能感兴趣的:(linux,运维,服务器)