Lazy loaded image
Words 0Read Time 1 min
Invalid Date
⚖️
核心判断
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 明明是小块高频对象,却还拿大块分配硬怼

这种设计通常不是高级,而是粗糙。

本章结论

  1. coherent、streaming、SG、cyclic 不是 API 菜单,而是系统取舍。
  1. coherent 更适合简单稳定的控制面,streaming 更适合高吞吐数据面。
  1. SG 解决分散数据组织,cyclic 解决持续周期流,两者都不是免费午餐。
  1. DMA pool 是 descriptor / command buffer 这类小块一致性内存的工程化解法。
  1. DMAEngine 适合复用标准能力,直控硬件适合高度私有语义。

什么时候优先看这一章

如果你已经不是“不懂 DMA”,而是卡在“到底该选哪条实现路径”,这一章最有用。
 
尤其适合下面几类场景:
  • 你在纠结控制面和数据面要不要分开选型。
  • 你怀疑单 buffer 已经不够,但又不确定是不是该上 SG。
  • 你面对音频 / ADC / 持续采集场景,不确定 cyclic 到底是不是天然更合适。
  • 你在 DMAEngine 和私有硬件直控之间摇摆,不知道自己到底需要复用还是需要掌控。

配套阅读

下一章要干什么

下一章进入最现实、也最容易翻车的一段:
  • 常见 bug 症状
  • timeout / reset / close / remove
  • 调试与验证
 
因为系统选型只是开局,真正把人折磨疯的,通常是错误路径和排障过程。
上一篇
Data Structure and Algorithm
下一篇
用面试拷问嵌入式技术栈

Comments
Loading...