LINUX MMC 子系统分析之五 MMC driver模块分析

       前面我们介绍了MMC 子系统驱动模型、mmc host模块,本篇主要介绍MMC Driver模块,在前面几篇文章中,我们已经说明mmc 子系统已实现mmc driver,即针对所有的mmc card(除 sdio设备外,包括mmc/sd/tf等存储卡),均可以使用该mmc driver。

 

下面我们分析下mmc 子系统为何实现了统一的mmc driver,主要有如下几点:

  1. Mmc host已提供了访问mmc card的方法(mmc_host->request);
  2. mmc/emmc/sd等协议规范均已定义mmc card(包括mmc/sd/tf等存储卡)支持的命令格式以及状态流转机制、寄存器定义等信息,因此可使用统一的驱动程序实现对所有厂家的card通信(这是由协议规范规定的,比如针对nandflash驱动模块,也不需要为nandflash设备实现特定驱动,因其协议规范也规定了nandflash需要支持的操作及通信格式等等)

基于以上几点,并不需要针对各厂家的mmc card,实现特殊的mmc driver,因此mmc 子系

统实现了统一的mmc driver;

 

本次介绍的内容包括如下几点:

一、相关的数据结构及关联说明

二、mmc driver的probe/remove

 

相关的数据结构及关联说明

 

    针对mmc driver而言,相关的数据结构包括mmc_driver、device_driver、device、mmc_card、mmc_part、mmc_blk_data、mmc_queue、gendisk、request_queue等;

     其中mmc_driver为一个mmc card驱动的抽象;device_driver、device为linux设备驱动模型相关的数据结构(该模块已在前面的文章中介绍,此处不再赘述);gendisk、request_queu、request_fn为块设备模型相关的数据结构(此处不展开);mmc_blk_data、mmc_queue主要用于实现mmc block device的通用块层与mmc host之间进行数据传输;而mmc_card则为mmc_driver所要驱动的外设。

这些数据结构之间的关联如下图所示,它们的关联关系说明如下:

  1. Mmc_driver与mmc_card,通过借助设备-总线-驱动模型的数据结构(device_driver、device)及接口,实现绑定与解绑操作;
  2. 针对mmc card,通过mmc_part可定义该mmc card的分区个数及分区大小等内容(mmc card中extended CSD寄存器中存储分区信息,当通过mmc rescan查找到mmc card时,会通过读取该寄存器的值,获取mmc card的分区信息);
  3. mmc_blk_data用于抽象mmc block device信息,这其中包括mmc_queue、request_queue、gendisk这些数据结构;

在完成mmc_driver与mmc_card的绑定过程中,在调用mmc_driver->probe进行设备探测时,则进行mmc block device的创建,针对每一个分区,均执行如下操作:

  1. 创建mmc_blk_data类型的变量,即为每一个分区均创建对应的通用块设备(gendisk类型);
  2. 创建mmc_queue,并为其创建对应的线程及处理接口(主要用于处理来自块I/O子系统的请求);
  3. 针对对mmc_queue,为其创建request_queue及其请求方法mmc_request_fn,并与gendisk进行关联;
  4. 将gendisk注册至块I/O子系统中,从而将本分区对应的通用块设备注册至块设备对应的bdev_map中,类似于字符设备的cdev_map;

 

本数据结构体包括了mmc driver 子系统、设备-总线-驱动模型、块设备驱动模型、mmc host子系统这几个模块。针对

mmc driver的probe而言,也就是完成如下图的数据结构间的关联(remove接口即解除这些数据结构间的关联)。

 

 

 

LINUX MMC 子系统分析之五 MMC driver模块分析

 

mmc_driver 数据结构

 

LINUX MMC 子系统分析之五 MMC driver模块分析

该数据结构主要包含了device_driver类型的成员,并定义了probe、remove、suspend、resume四个函数指针;这四个函数指针的功能与device_driver中对应的函数指针时对应的。

 

struct mmc_card数据结构

该数据结构已在上一篇文章中说明,此处不再赘述;

struct mmc_part数据结构

该数据结构用于描述一个mmc card 分区,主要包括分区大小、分区的类型、分区名称、是否为只读分区等信息。mmc

card中extended CSD寄存器中存储分区信息,当通过mmc rescan查找到mmc card时,会通过读取该寄存器的值,获取mmc card的分区信息

 

LINUX MMC 子系统分析之五 MMC driver模块分析

 

 

struct mmc_blk_data数据结构

该数据结构用于抽象一个mmc card 分区对应的block device的数据信息,其中包括:

  1. 该分区对应的通用磁盘设备gendisk,用于将该分区注册至块设备层,以便应用程序可通过块设备I/O访问该分区;
  2. mmc_queue用于抽象mmc 块设备的请求队列,该数据结构中包括了块设备请求队列成员(request_queue及其访问方法,用于处理块I/O层的数据请求信息,并实现将请求分发给mmc host,进而完成与mmc card的数据通信);
  3. 链表成员part用于将该mmc card所有分区对应的mmc_blk_data变量链接至一起;
  4. force_ro、power_ro_lock主要用于描述该分区对应块设备的设备属性信息。

 

LINUX MMC 子系统分析之五 MMC driver模块分析

 

 

 

struct mmc_queue数据结构

该数据结构用于描述块设备I/O的request请求,该数据结构包含的内容如下:

  1. card用于指向该队列对应的mmc_card;
  2. thread用于描述该mmc_queue对应的线程,该线程主要用于处理所有从块I/O层下发的请求(request_queue);
  3. request_queue类型的变量用于向块I/O层注册request_queue及其请求方法,以便块I/O层可以将上层的数据请求下发至mmc  block层;
  4. issue_fn用于mmc block层将数据请求下发给mmc host层,由mmc host层继续实现数据请求的处理。

LINUX MMC 子系统分析之五 MMC driver模块分析

 

Mmc block层的块I/O请求处理

      Mmc block层主要借助mmc_queue类型的变量实现块i/o请求,mmc block层提供了块i/o请求处理的线程。块i/o层接口层通过调用mmc block层的request方法(即request_queue->request_fn,即mmc_request_fn接口),该方法通过调用wake_up_process接口,唤醒mmc block层的块i/o处理线程,该线程处理接口则调用mq->issue_fn进行i/o请求的分发,即调用mmc_blk_issue_rq接口,该接口通过一系统的接口调用,最终即调用mmc_host->ops->request,通过mmc_host提供的方法,实现与mmc_card的通信操作。Mmc block层的块i/o处理流程如下所示。

 

 

LINUX MMC 子系统分析之五 MMC driver模块分析

 

 

mmc driver的probe/remove

       上面介绍了mmc driver层相关的数据结构,通过这些数据结构间的关联图,基本上对mmc driver 的probe/remove接口也有了一定的了解,而mmc driver的probe/remove接口,也就是完成上述数据结构间的关联的建立与消除。

 

mmc_driver的定义如注册

mmc_driver的定义如下,该driver的名称为“mmcblk”,主要实现了probe/remove接口以及suspend/resume接口(这两

个接口主要用于电源管理)。

 

LINUX MMC 子系统分析之五 MMC driver模块分析

 

mmc_driver与mmc_card的绑定流程

mmc_driver与mmc_card借助设备-总线-驱动模型提供的接口完成,mmc_driver与mmc_card绑定,并执行mmc_driver->probe接口。mmc_driver、mmc_card、mmc_bus之间的绑定流程如下所示:

  1. 通过driver_register与device_register,从而完成mmc_driver、mmc_card、mmc_bus之间的绑定。

(当mmc rescan一个mmc card后,则会创建mmc card,并同时调用device_register,将该mmc_card注册至mmc_bus中,并触发__device_attach,从而完成mmc_card与mmc_driver的绑定,并调用mmc_driver->probe,即调用mmc_blk_probe接口,实现mmc block device的创建及注册流程。)

LINUX MMC 子系统分析之五 MMC driver模块分析

 

mmc_blk_probe

mmc_blk_probe实现的功能如下:

针对该mmc card的每一个分区,均执行如下操作:

  1. 为每一个分区,创建对应的通用磁盘设备gendisk;
  2. 设置gendisk的fops为mmc_bdops;
  3. 为每一个通用磁盘设备,均创建request_queue及其处理方法;
  4. 为该通用磁盘设备创建mmc block块i/o请求机制;
  5. 将该分区对应的通用磁盘设备注册至块设备i/o中,以便应用层可通过块设备访问该mmc card 分区。

 

LINUX MMC 子系统分析之五 MMC driver模块分析

 

 

mmc_driver与mmc_card的解绑流程

      当mmc card rescan机制,检测到mmc card移除后,在mmc card release的过程中,即调用device_unregiser接口,完成解绑流程,从而触发mmc_blk_remove接口的调用,完成解绑操作。而mmc_blk_remove接口的主要功能如下:

针对每一个mmc card分区,均执行如下操作:

  1. 将该分区对应的mmc 块请求处理机制删除;
  2. 将该分区对应的通用磁盘设备从块设备模块中移除;
  3. 解除mmc_card与mmc_host的关联;

 

LINUX MMC 子系统分析之五 MMC driver模块分析

 

 

        以上即为本篇文章的主要内容,本篇文章主要说明mmc_driver与mmc_card的绑定与解绑流程,并说明了mmc block device的创建与删除流程等内容,本章的内容不需要驱动开发人员进行更改,这些内容均为mmc子系统实现,此处主要用于帮助我们理解mmc子系统。