核心判断
DMA 设计里最致命的误区之一,是把 coherent、streaming、SG、cyclic 当成“API 菜单”。它们不是菜单,而是不同的系统取舍:谁更简单、谁更快、谁更适合流式、谁更吃治理能力,完全不是一回事。
这一章解决什么问题
前面我们已经把:
- 数据路径
- ownership
- 生命周期
- 用户态协议
都搭起来了。
接下来要做的是更难的一步:
选型。
也就是在真实项目里回答:
- 到底该用 coherent 还是 streaming?
- 单块 buffer 不够时,何时进入 SG?
- 持续流场景为什么经常走 cyclic?
- 该借 DMAEngine,还是自己直控硬件?
- descriptor 这种小块一致性内存,是直接大块分配还是 pool 化?
先给结论:没有“最好”,只有“最合适”
如果你的目标是:
- 心智负担低
- 正确性优先
- 数据量没那么夸张
那么 coherent 往往更友好。
如果你的目标是:
- 高吞吐
- 长时间持续流
- 更细致控制 cache / 生命周期
那么 streaming 往往更常见。
而 SG、cyclic、DMAEngine、DMA pool,则是更进一步的结构性选择,不是简单替代关系。
coherent vs streaming:核心差别到底在哪
维度 | coherent | streaming |
心智负担 | 低 | 高 |
同步复杂度 | 相对低 | 高,需要显式治理 |
适合场景 | 简单控制面、小规模共享结构 | 高吞吐、流式、大块数据路径 |
性能灵活性 | 中等 | 更强 |
容易翻车点 | 误以为所有问题都天然解决 | sync、ownership、回收全都得管 |
coherent 更像什么
更像“语义友好型内存”:
- descriptor
- ring 元数据
- 状态页
- 小块控制结构
它适合帮助你把系统先做对。
streaming 更像什么
更像“高性能数据通路”:
- 大块 payload
- 持续收发
- 用户态零拷贝前后链路
它适合把系统做快,但前提是你已经有足够的治理能力把生命周期管住。
一个非常实用的划分思路
控制面用 coherent
比如:
- descriptor ring
- 状态页
- 少量元数据
数据面用 streaming
比如:
- 大块 payload buffer
- 持续 RX/TX 的主数据区
这类混合设计在工程上很常见,因为它兼顾了:
- 控制面简单
- 数据面高效
API 视角下,这些选择分别落到哪里
设计选择 | 常见 API / 机制 | 典型落点 |
coherent | dma_alloc_coherent() / dma_free_coherent() | descriptor、ring、长期控制结构 |
streaming | dma_map_single() / dma_unmap_single() / dma_sync_*() | 大块数据面、重复收发 buffer |
SG | dma_map_sg() / dma_unmap_sg() | 分散内存拼成一条传输 |
小块一致性内存池 | dma_pool_create() / dma_pool_alloc() | 频繁分配的小 descriptor / command buffer |
平台抽象 | DMAEngine 回调与框架 | 标准化 DMA 控制器能力 |
DMA pool:什么时候该用
这玩意很容易被忽略,但它非常工程化。
当你面对的是:
- 很多小块一致性 DMA 内存
- 频繁分配 / 释放
- 对齐、边界要求严格
这时直接反复
dma_alloc_coherent() 往往既笨又重。更合适的方式是给 descriptor / command buffer 建一层 pool。适合 DMA pool 的对象
- 小 descriptor
- command buffer
- 固定尺寸 ring entry
不适合 DMA pool 的对象
- 大块 payload
- 生命周期很长且数量极少的大 buffer
- 本质上更像 streaming 数据面的东西
SG(scatter-gather)到底是在解决什么
SG 的本质不是“高级玩法”,而是解决:
数据不一定天然连续,但设备处理又希望像一整段。
它适合:
- 大块数据分散在多段内存
- 减少人为拼接/复制
- 提高复杂数据通路的灵活性
什么时候考虑 SG
- 单一连续大 buffer 成本高
- 数据天然分块
- 设备本身就支持 SG descriptor
什么时候别急着上 SG
- 你现在连单 buffer 生命周期都没管明白
- 系统还处在“先跑通”阶段
- 真正瓶颈不在复制,而在状态机混乱
说白了:SG 能提高吞吐上限,也能成倍扩大你的调试半径。
cyclic DMA 为什么总在音频、采集里出现
因为它天生适合:
- 周期性数据到达
- ring 式持续处理
- 一边采、一边消费
它的核心不是“环形很酷”,而是:
设备和软件都默认这条数据流不会只跑一次。
典型场景:
- 音频播放/录制
- ADC 周期采样
- 持续传感器采集
cyclic 的代价
- 更依赖稳定的回调/完成节奏
- 更依赖明确的 period / buffer 边界
- 一旦回收或完成语义模糊,就容易出现丢 period、错位、撕裂
DMAEngine vs 自己直控硬件
DMAEngine 适合什么
- 平台已有通用 DMA 子系统
- 设备传输模式较标准
- 你不想重复造轮子
- 你更希望复用通用接口和回调模型
自己直控硬件适合什么
- 设备 DMA 逻辑非常私有
- descriptor / ring 语义高度定制
- 通用抽象层包不住真实需求
选型本质
不是“哪个更高级”,而是:
- 你的设备语义是否能被通用抽象承载
- 你需要的是复用,还是强定制控制
如果设备行为已经很私有,却硬往 DMAEngine 套,最后往往不是优雅,而是抽象层和硬件语义互相伤害。
一张工程决策表
场景 | 更常见选择 | 原因 |
小规模控制结构 | coherent | 简单、稳定、心智负担低 |
高频小块 descriptor | coherent + DMA pool | 对齐友好、频繁分配成本更低 |
大块持续数据面 | streaming | 更适合高吞吐路径 |
分散数据拼成一条传输 | SG | 减少复制,提高灵活性 |
周期性持续采集/播放 | cyclic | 天然适合 ring/period 模型 |
标准化平台 DMA 能力 | DMAEngine | 复用成熟抽象 |
高度私有的硬件队列语义 | 直控硬件 | 避免被通用抽象绑手绑脚 |
一套你真能拿去用的选型检查表
先问场景
- 是一次性搬运,还是持续流?
- 是控制面,还是数据面?
- 是否需要用户态零拷贝?
再问吞吐与复杂度
- 真的需要高性能数据通路吗?
- 现阶段的系统能否承受 streaming/SG/cyclic 带来的复杂度?
再问硬件边界
- 硬件 descriptor 模型是否天然支持 SG / cyclic?
- DMAEngine 的抽象是否覆盖设备语义?
- 小块内存对象是否值得池化?
再问调试能力
- 你是否已经有状态机、日志、reset、回收治理?
- 如果没有,先别上最复杂的形态
最容易犯的选型错误
错误 1:为了性能,默认选最复杂的
很多系统根本还没到性能瓶颈,先死在生命周期和异常路径上。
错误 2:把 coherent 当成“万能保险”
它可以降低一致性心智负担,但不会替你解决 ownership、协议和 reset。
错误 3:把 SG / cyclic 当成“进阶就一定更好”
不是更好,只是更适合某些场景,也更要求纪律。
错误 4:descriptor 明明是小块高频对象,却还拿大块分配硬怼
这种设计通常不是高级,而是粗糙。
本章结论
- coherent、streaming、SG、cyclic 不是 API 菜单,而是系统取舍。
- coherent 更适合简单稳定的控制面,streaming 更适合高吞吐数据面。
- SG 解决分散数据组织,cyclic 解决持续周期流,两者都不是免费午餐。
- DMA pool 是 descriptor / command buffer 这类小块一致性内存的工程化解法。
- DMAEngine 适合复用标准能力,直控硬件适合高度私有语义。
什么时候优先看这一章
如果你已经不是“不懂 DMA”,而是卡在“到底该选哪条实现路径”,这一章最有用。
尤其适合下面几类场景:
- 你在纠结控制面和数据面要不要分开选型。
- 你怀疑单 buffer 已经不够,但又不确定是不是该上 SG。
- 你面对音频 / ADC / 持续采集场景,不确定 cyclic 到底是不是天然更合适。
- 你在 DMAEngine 和私有硬件直控之间摇摆,不知道自己到底需要复用还是需要掌控。
配套阅读
- 04|Ownership、协议与生命周期:DMA 设计的中轴:先立规则,再谈选型,否则你只是在挑更复杂的坑。
- 07|mmap 零拷贝与用户态协作:接口协议比映射更重要:如果你要做用户态零拷贝,本章选型会直接影响协议设计。
- 10|真实驱动源码拆解:从成熟实现里看取舍:把这一章的抽象选择映射回真实驱动案例。
- 12|API、模板与快查附录:需要 API 级速查时,别在正文里翻来翻去。
下一章要干什么
下一章进入最现实、也最容易翻车的一段:
- 常见 bug 症状
- timeout / reset / close / remove
- 调试与验证
因为系统选型只是开局,真正把人折磨疯的,通常是错误路径和排障过程。






