2. Linux DMA子系统架构:dmaengine框架、dma_device结构体、dma_chan通道模型

在Linux内核中,DMA(Direct Memory Access)子系统通过一套统一的框架——dmaengine,为设备驱动开发者提供了标准化的DMA操作接口。本章将深入剖析dmaengine框架的层次结构、核心数据结构dma_device以及通道模型dma_chan,帮助您理解DMA子系统如何实现从“硬件控制器”到“软件抽象”的完整映射。

2.1 dmaengine框架:三层架构与设计哲学

dmaengine框架的设计遵循“分层抽象、统一接口”的原则,将DMA控制器硬件差异封装在底层,向上层驱动提供一致的API。其整体架构可分为三层:

  • DMA引擎核心层(Core Layer):提供框架初始化、通道管理、事务调度等通用逻辑。
  • DMA控制器驱动层(Controller Driver):由芯片厂商实现,负责填充dma_device结构体,注册到核心层。
  • DMA用户层(Consumer/User):包括网络、存储、音频等子系统驱动,通过dmaengine API发起DMA传输请求。
设计要点: dmaengine框架通过“回调函数”和“描述符”机制,将硬件DMA通道抽象为软件可管理的资源,支持同步、异步、循环等多种传输模式。
dmaengine 三层架构图 dmaengine 框架三层架构 用户层(Consumer) 网络驱动 / 存储驱动 / 音频驱动 / 其他外设驱动 核心层(Core Layer) dmaengine API / 通道管理 / 描述符调度 / 事务队列 控制器驱动层(Controller Driver) dma_device 填充 / 硬件寄存器操作 / 中断处理 说明:用户层通过标准API调用核心层,核心层调度控制器驱动层完成实际DMA传输

2.2 dma_device结构体:DMA控制器的软件抽象

dma_device是DMA控制器驱动向核心层注册的核心数据结构,它描述了一个DMA控制器的全部能力、资源与操作函数。该结构体定义在include/linux/dmaengine.h中,主要字段如下:

字段 类型 描述
dev struct device * 指向DMA控制器的设备结构体,用于驱动模型绑定
channels struct list_head 该控制器管理的所有DMA通道链表头
cap_mask dma_cap_mask_t 位掩码,标识控制器支持的DMA传输类型(如MEMCPY、SG、CYCLIC等)
directions unsigned long 支持的DMA方向位图(DEV_TO_MEM、MEM_TO_DEV、MEM_TO_MEM)
src_addr_widths unsigned long 支持的源地址宽度位图(8位、16位、32位、64位)
dst_addr_widths unsigned long 支持的目的地址宽度位图
device_alloc_chan_resources 函数指针 分配并初始化通道硬件资源
device_free_chan_resources 函数指针 释放通道硬件资源
device_prep_dma_memcpy 函数指针 准备内存到内存的DMA传输描述符
device_prep_slave_sg 函数指针 准备外设与内存间的SG(Scatter-Gather)传输描述符
device_issue_pending 函数指针 将已提交的描述符推送到硬件执行
device_tx_status 函数指针 查询传输状态(已完成字节数、错误码等)
实战提示: 在编写DMA控制器驱动时,cap_mask和directions的配置直接影响上层驱动能否成功请求通道。例如,若控制器不支持DMA_SLAVE能力,则外设驱动无法通过dma_request_channel()获取通道。
dma_device 结构体关系图 dma_device 结构体核心字段关系 dma_device cap_mask 传输类型能力位图 directions DMA方向位图 device_* 函数指针 alloc/prep/issue/status channels dma_chan 链表头 src/dst_addr_widths 地址宽度位图 说明:dma_device 通过 channels 链表管理多个 dma_chan,每个通道对应一个硬件DMA通道

2.3 dma_chan通道模型:从硬件通道到软件句柄

dma_chan是DMA通道在软件层面的抽象,代表一个可独立调度和使用的DMA传输资源。每个dma_chan实例对应一个硬件DMA通道,并包含以下关键信息:

  • 设备归属:device指针指向所属的dma_device,建立通道与控制器的关联。
  • 客户端信息:client指针指向当前使用该通道的消费者驱动,用于权限管理和回调通知。
  • 描述符队列:desc链表用于管理已提交但尚未完成的传输描述符。
  • 状态与配置:包括通道是否空闲、是否循环模式、中断配置等。
通道生命周期: 请求通道(dma_request_channel)→ 配置通道(dmaengine_slave_config)→ 提交描述符(dmaengine_submit)→ 启动传输(dma_async_issue_pending)→ 传输完成回调 → 释放通道(dma_release_channel)。

2.3.1 通道分配策略

dmaengine框架支持两种通道分配策略:

策略 API 适用场景
基于能力匹配 dma_request_channel() 根据cap_mask和过滤函数自动匹配可用通道
基于设备树/平台数据 dma_request_slave_channel() 通过设备树节点或平台数据指定通道名称,适用于外设与DMA通道固定绑定的场景
dma_chan 通道状态机 dma_chan 通道状态转换图 空闲(Idle) 已分配(Allocated) 传输中(Active) 完成(Completed) dma_request_channel dma_async_issue_pending 传输完成中断 dma_release_channel 说明:通道从空闲到完成构成完整生命周期,每个状态转换由dmaengine API触发

2.4 核心数据结构关系总览

为了帮助您建立全局认知,下表总结了dmaengine框架中三个核心数据结构的分工与协作关系:

数据结构 职责 关键关联
dma_device 描述DMA控制器的能力、资源和操作函数 通过channels链表管理多个dma_chan
dma_chan 抽象单个DMA通道,维护传输状态和描述符队列 通过device指针关联dma_device
dma_async_tx_descriptor 描述一次DMA传输任务,包含源地址、目的地址、长度、回调等 由dma_device的device_prep_*函数创建,提交到dma_chan的队列
常见误区: 初学者容易混淆dma_device和dma_chan的关系。请记住:dma_device是“控制器”,dma_chan是“通道”。一个控制器可以拥有多个通道,但每个通道只能属于一个控制器。在驱动开发中,您通常操作的是dma_chan句柄,而不是直接操作dma_device。

2.5 本章小结

本章详细介绍了Linux DMA子系统的核心架构:

  • dmaengine框架采用三层分层设计,实现了硬件无关的DMA编程接口。
  • dma_device结构体是DMA控制器的软件抽象,通过能力位图、方向位图和函数指针暴露硬件能力。
  • dma_chan通道模型将硬件通道封装为可分配、配置、提交和释放的软件资源,具有清晰的生命周期状态机。