Edit online

关键流程设计

Read time: 3 minute(s)
Edit online

初始化流程

Read time: 3 minute(s)

MMC 子系统的初始化包括 MMC 块设备、MMC 子系统、MMC 控制器驱动、card 设备等几条线,初始化顺序:

  1. MMC 核心初始化
  2. MC 控制器驱动初始化完成后才会对 card 设备进行初始化
  3. MMC 块设备初始化没有严格的先后顺序

MMC 块设备驱动初始化

MMC 在使用中,会将其抽象成一个块设备挂载到通用块层当中,通过 module_init(mmc_blk_init) 完成注册和初始化的操作,主要步骤如下:

  1. 注册总线 (bus_register)。
  2. 将块设备名 ”mmc” 和主设备注册到块层中 (register_blkdev)。
  3. 将 driver 设备驱动注册到驱动模型中 (mmc_register_driver)。
  4. 块设备的初始化及磁盘分区的注册 (mmc_blk_probe)。

MMC 子系统核心初始化

MMC 子系统的核心层负责处理 block 下达的请求,其中关于 MMC 协议的逻辑主要在此实现,通过 subsys_initcall(mmc_init) 完成初始化,其步骤如下:

  1. MMC 类型总线注册 (mmc_register_bus)。
  2. 为控制器设备注册一个类 (mmc_register_host_class)。
  3. SDIO 类型总线类型注册 (sdio_register_b)。

card 设备注册与初始化

MMC 驱动的访问对象为外设,在子系统中会将外设抽象成一个 card 设备,在每次探测外设的时候都会判断该设备是否需要被注册,所以 card 设备注册介绍分为探测时机和注册过程两部分:

  1. 探测时机:
    • mmc 控制器启动时
    • 热插拔时
    • mmc 控制器从 suspend 转为 resume 时
    • 上述三种情况均会进行一次探测,都会调用到函数 mmc_detect_change
  2. 注册过程:
    在探测时调用的函数 mmc_detect_change,该函数会调用 card 设备的注册函数 mmc_rescan,以 SD 卡为例,其注册和初始化过程如下:
    • 判断当前卡是否被注册
    • 若卡已经注册,则确认卡是否存在,存在则提前跳出,若不存在则释放相关资源
    • 若卡未注册,则启动控制器进行卡的初始化步骤
    • 为控制器绑定具体总线的操作函数(mmc_attach_bus(host, &mmc_sd_ops))
    • 适配卡的工作电压 (mmc_select_voltage)
    • 根据 MMC 协议初始化卡,使卡进入传输模式化 (mmc_sd_init_card)
    • 注册卡设备 (mmc_add_card)

控制器驱动注册与初始化

MMC 控制器驱动通过对控制器进行操作完成核心层的请求,控制器驱动也是实现和外设进行通信的软件最底层驱动,该层驱动根据厂商不同而不同,D211 的 SDMC 模块的控制器驱动通过 module_platform_driver(artinchip_mmc_aic_pltfm_driver) 实现,其主要步骤如下:

  1. 使能时钟 (artinchip_mmc_clk_enable)。
  2. 初始化计时机制,该机制实现发送命令和数据传输的 timeout 机制 (timer_setup)。
  3. 初始化保护锁 (spin_lock_init)。
  4. 初始化 tasklet,在驱动中很多流程的处理会在 tasklet 中 (tasklet_init)。
  5. 初始化 DMA(artinchip_mmc_init_dma)。
  6. 中断初始化和注册 (devm_request_irq)。
  7. 注册具体的控制器 (mmc_alloc_host + mmc_add_host)。
  8. 初始化具体控制器,包括接口函数、工作电压、传输能力等。
Edit online

中断处理流程

Read time: 3 minute(s)

在触发中断后,需要根据目前的中断状态进行处理,其中主要为错误处理和传输处理,这些处理主要在 tasklet 中,并且基于一些状态变量来控制处理的流程。

  1. 状态变量。在流程的控制上,主要通过几个状态变量来控制:
    • host-> state:表示当前的操作状态,例如发送数据,发送 CMD 等等

    • host->pending_events:当前中断发生的状态

    • host->completed_events:当前完成的状态,例如 CMD 完成,DATA 完成等

    • host->cmd_status:发送 CMD 时中断的状态

    • host->data_status:传输数据时中断的状态

  2. 传输处理
    • 当 CMD 发送完成中断触发后,会在 tasklet 中调用函数 complete,该函数中会读取外部 SD 设备返回给控制器的 response 数据,再根据当前的 CMD 状态对 CMD 的结果进行赋值。

    • 如果使用的是 PIO 的方式,当 TX/RX FIFO 请求中断响应后,会调用对应的函数对 FIFO 进行读写操作。

    • 若是采用 DMA 的方式,则在中断函数中读取内部 DMA 状态,然后释放 DMA 传输的资源,再根据 DMA 的状态,在 tsaklet 中调用 artinchip_mmc_data_complete 函数,该函数会根据目前的数据传输情况对传输结果进行赋值。

  3. 错误处理。目前 SDMC 支持的错误中断类型包括:
    • CMD 错误中断

      当出现 CMD 错误中断后,在中断处理函数中,会将当前中断寄存器的状态保存,然后设置 cmd 的状态为已经完成,最后在 complete 函数中将 CMD 的结果进行赋值。

    • DATA 错误中断

      当出现 DATA 中断后,在中断处理函数中会将当前的中断状态保存,然后设置 data 的状态为 DATA 错误,然后切入到 tasklet 函数中,在该函数中,根据 DATA 错误的状态,停止 dma,如果有需求,就发送 stop 命令。

Edit online

请求处理流程

Read time: 3 minute(s)

对于应用程序,通过读写的接口访问文件系统,文件系统访问块设备,MMC 设备在内核中被注册为一个块设备,当读写的操作传入到 MMC 块设备后,通过 MMC 子系统处理相关操作,对于 MMC 子系统其处理皆以请求的方式实现。

块层以上系统读写调用流程

在块层以上,通常是用户空间调用读写接口访问 MMC 设备,主要流程如下:


blkdev_access_flow

1. 通用块设备的访问流程
  1. 在用户空间,应用程序调用 read/write 接口
  2. 然后通过虚拟文件系统
  3. 调用通用块层的接口对块设备进行 IO 请求
  4. IO 调度层负责使用特定算法对这些请求进行调度
  5. 块设备驱动层调用具体的块设备接口访问设备

MMC 子系统请求处理流程

MMC 子系统被抽象成一个块设备,通用块层将 IO 请求调用到具体的块设备驱动层,在 MMC 块设备驱动中的请求处理流程如下:


mmc_request_flow

2. MMC 数据请求的处理流程
  1. 由于会有多个请求,在 block 中以队列的形式处理,在请求到达时,唤醒 mmc_queue_thread。
  2. 调用 block 的请求处理,发出 request。
  3. block 的 request 会由 core 来实现。
  4. core 层会根据当前 host 驱动调用对应 host 的 ops 中的 request 接口去操作 controller。

函数调用关系:

mmc_wait_for_req
|--__mmc_start_req
|--init_completion
            |--mmc_start_request
                |--mmc_mrq_prep
                |--__mmc_start_request
                    |--trace_mmc_request_start
                    |--host->ops->request (即 request)

Host 层驱动请求处理流程

在访问 MMC 外设时,都是通过发送 CMD 的方式,在 host 层驱动中需要通过操作 controller 去实现 core 层的 request,主要流程如下:


host_request_flow

3. Host 层驱动的请求处理流程
  1. 检测卡设备,需要判断当前卡设备是否被拔出。
  2. 判断传输状态,如果当前传输状态不是 idle,那么将会将该请求放在请求队列里。
  3. 处理 data,如果当前请求需要处理数据,则将数据先行处理,如果不需要处理数据则跳过。
  4. 发送 CMD,解析请求中的 CMD 和参数,将其写入寄存器,然后触发 CMD 的发送。
  5. 中断处理,在发送完 CMD 后,后续的工作需要等待中断的触发,在中断处理中会对外设返回的数据和状态进行处理。
  6. 如果需要,发送 stop 命令,结束该次传输。
Host 层函数调用关系:
artinchip_mmc_request
|--artinchip_mmc_get_cd
|--artinchip_mmc_queue_request
|--artinchip_mmc_start_request
        |--artinchip_mmc_prepare_command
        |--artinchip_mmc_submit_data
        |--artinchip_mmc_start_command
        |--artinchip_mmc_prep_stop_abort