ARM架构MMC块设备驱动参数配置与性能调优 - 第1节

1.1 MMC/SD/eMMC 协议演进

MMC(MultiMediaCard)协议自 1997 年由西门子和 SanDisk 推出以来,经历了从机械卡到嵌入式存储芯片的完整演进。理解协议代际差异是配置驱动参数和调优性能的前提。

协议版本 推出年份 总线宽度 最高时钟频率 理论峰值速率 关键特性
MMC 3.x 1997 1-bit 20 MHz 2.5 MB/s SPI 模式、串行通信
MMC 4.x 2002 1/4/8-bit 52 MHz 52 MB/s 多块传输、分区、Boot 分区
SD 1.0 / 2.0 2001 1/4-bit 25 / 50 MHz 12.5 / 25 MB/s CPRM 版权保护、SDHC
SD 3.0 (UHS-I) 2010 4-bit 208 MHz (DDR) 104 MB/s SDR104/DDR50 模式
eMMC 4.4 / 4.5 2009 1/4/8-bit 52 / 200 MHz (HS200) 200 MB/s HS200、Cache、Reliable Write
eMMC 5.0 / 5.1 2013 1/4/8-bit 200 MHz (HS400) 400 MB/s HS400、Command Queue、FFU
UFS 2.x / 3.x 2014 全双工差分 2.9 / 5.8 Gbps/lane 1.45 / 2.9 GB/s SCSI 命令集、多队列
调优要点: eMMC 5.0 引入的 HS400 模式需要双沿采样和 CRC 校验,ARM 平台的 MMC 控制器必须正确配置 DLL 延迟线,否则高频下会出现 CRC 错误。这是嵌入式调优中最常见的硬件-软件协同问题。
MMC/SD/eMMC 协议演进时间线 MMC 3.x 1997 MMC 4.x 2002 SD 2.0 2006 eMMC 4.5 2009 eMMC 5.1 2013 演进趋势: • 总线宽度:1-bit → 4-bit → 8-bit → 全双工差分 • 时钟频率:20 MHz → 200 MHz (DDR) → 5.8 Gbps/lane • 命令队列:无 → 单队列 (eMMC CQ) → 多队列 (UFS)

1.2 Linux MMC 子系统架构

Linux MMC 子系统采用分层设计,从上到下依次为:块设备层、MMC 核心层、MMC 主机控制器驱动层。每一层都定义了清晰的接口,使得驱动开发与协议细节解耦。

1.2.1 三层架构职责

层次 内核路径 核心职责 关键文件
块设备层 block/ 提供通用块 I/O 请求队列、I/O 调度、bio 处理 block/blk-core.c, block/elevator.c
MMC 核心层 drivers/mmc/core/ 协议状态机、命令/数据传输、卡识别、电源管理 mmc.c, sd.c, mmc_ops.c
主机控制器层 drivers/mmc/host/ 硬件寄存器操作、DMA 配置、中断处理、时钟调优 sdhci.c, dw_mmc.c, omap_hsmmc.c
Linux MMC 子系统三层架构 块设备层 (Block Layer) I/O 调度器 · bio 请求 · 块设备注册 · 分区管理 MMC 核心层 (MMC Core) 协议状态机 · 命令/响应 · 卡识别 · 总线模式切换 主机控制器层 (Host Controller) SDHCI · dw_mmc · omap_hsmmc · 寄存器级操作 硬件设备 (eMMC / SD / SDIO) 数据流方向

1.2.2 核心层关键组件

MMC 核心层是子系统的中枢,负责管理卡的生命周期和协议交互。以下为核心层的主要模块:

  • mmc_alloc_card / mmc_add_card:卡识别阶段,通过 CMD2/CMD3 获取 CID 并分配卡结构体。
  • mmc_init_card:卡初始化,包括电压匹配、总线宽度协商、高速模式使能。
  • mmc_set_ios:设置 I/O 参数(时钟、总线宽度、电压、驱动强度),是调优的核心入口。
  • mmc_start_request:将块设备层的请求转换为 MMC 命令序列,支持单块/多块/预擦除。
  • mmc_wait_for_req:同步等待命令完成,处理超时和 CRC 错误重试。
关键数据结构: struct mmc_card 是核心层最重要的结构体,包含卡类型、时序模式、最大频率、块长度、分区信息等。驱动调优时,通过 mmc_card->ext_csd 访问 eMMC 扩展寄存器,获取 HS400 支持、Cache 大小、擦除分组等信息。

1.3 块设备层与 MMC 核心层的关系

块设备层与 MMC 核心层通过 请求队列 (request queue) 和 块设备操作函数 (block_device_operations) 进行交互。MMC 核心层向块设备层注册为一个块设备,并实现 mmc_blk_ops 回调。

1.3.1 交互流程

  1. bio 提交:文件系统通过 submit_bio 将 I/O 请求提交到块设备层的请求队列。
  2. I/O 调度:块设备层的 I/O 调度器(如 CFQ、deadline、mq-deadline)对 bio 进行合并和排序。
  3. 请求分发:MMC 块设备驱动 (mmc_block.c) 从请求队列中取出请求,调用 mmc_blk_issue_rq。
  4. 命令组装:核心层将请求转换为 MMC 命令(如 CMD18/CMD25 多块读写),填充 struct mmc_request。
  5. 硬件执行:主机控制器驱动通过 DMA 或 PIO 执行数据传输,完成后触发中断。
  6. 完成回调:核心层调用 mmc_blk_rw_rq_prep 中的完成函数,通知块设备层 I/O 结束。
块设备层 ↔ MMC 核心层交互流程 文件系统 (VFS) submit_bio 块设备层 (Block Layer) 请求队列 · I/O 调度 · bio 合并 mmc_blk_issue_rq MMC 块驱动 (mmc_block) 请求拆分 · 命令组装 · 完成回调 mmc_start_request MMC 核心层 (MMC Core) 协议状态机 · 命令序列 · 错误重试 关键接口: • submit_bio • blk_fetch_request • mmc_blk_issue_rq • mmc_start_request • mmc_wait_for_req • blk_end_request 数据流向: bio → request → mmc_request → host 命令执行

1.3.2 关键数据结构关系

块设备层与 MMC 核心层之间的数据传递通过以下核心结构体完成:

结构体 所属层次 作用 关键字段
struct request 块设备层 表示一个 I/O 请求,包含 bio 链表、扇区号、方向 cmd_flags, __sector, bio
struct mmc_blk_request MMC 块驱动 将块请求转换为 MMC 命令的中间结构 mrq, cmd, data, stop
struct mmc_request MMC 核心层 核心层使用的命令/数据/停止三元组 cmd, data, sbc, done
struct mmc_command MMC 核心层 单条 MMC 命令,包含命令号、参数、标志 opcode, arg, flags, resp
struct mmc_data MMC 核心层 数据传输描述,包含 SG 表、块数、块大小 sg, blocks, blksz, flags
常见误区: 初学者常混淆 struct mmc_blk_request 和 struct mmc_request。前者是块驱动层的封装,包含多个 MMC 命令(如预擦除 + 写命令);后者是核心层的单一命令/数据单元。调优时,如果需要在块驱动层插入自定义命令(如 Cache Flush),必须操作 mmc_blk_request 中的 mrq 字段。

1.3.3 性能关键路径

从块设备层到 MMC 核心层的完整路径中,以下环节直接影响 I/O 性能:

  • I/O 调度器选择:eMMC 设备建议使用 mq-deadline 或 none,避免 CFQ 带来的额外延迟。
  • 请求合并:块设备层会合并相邻扇区的 bio,减少 MMC 命令数量。通过 /sys/block/mmcblk0/queue/max_sectors_kb 控制最大合并大小。
  • DMA 映射:MMC 核心层通过 dma_map_sg 将 SG 表映射到 DMA 地址,ARM 平台需注意 cache 一致性维护。
  • 命令排队:eMMC 5.0 支持命令排队 (CQ),块设备层通过 blk-mq 多队列框架与核心层交互,减少锁竞争。
// 块设备层请求队列参数示例 (sysfs 调优)
// 查看当前队列参数
cat /sys/block/mmcblk0/queue/max_sectors_kb
cat /sys/block/mmcblk0/queue/max_segments
cat /sys/block/mmcblk0/queue/io_poll

// 设置最大扇区数为 1024 KB (适合大块顺序读写)
echo 1024 > /sys/block/mmcblk0/queue/max_sectors_kb

// 设置 I/O 调度器为 mq-deadline
echo mq-deadline > /sys/block/mmcblk0/queue/scheduler
ARM 平台特别提示: 在 ARM 架构中,MMC 主机控制器通常挂在 AXI 总线上。块设备层与 MMC 核心层之间的数据缓冲区必须进行 cache 刷新操作(dma_map_sg 自动处理),否则会出现数据不一致导致的 CRC 错误。调试时可通过 CONFIG_DMA_API_DEBUG 检测 DMA 映射问题。