系统服务 · DMA
1. 模块概述
- 主要功能:基于
/dev/me_dma内核驱动的用户态 DMA 拷贝库,提供高速内存传输能力,支持 dma-buf 的同步/异步拷贝,可用于零拷贝或高效内存传输场景 - 规格或特性:
- 支持三种传输方向:MEM_TO_MEM(内存到内存)、MEM_TO_DEV(内存到设备)、DEV_TO_MEM(设备到内存)
- 支持同步/异步传输模式
- 支持中断回调和循环模式(用于音视频流)
- 与 libshm 配合实现跨进程零拷贝传输
- 相关目录结构:
components/system/dma/
├── include/dma.h # 对外 API 头文件
├── src/ # 库实现源码
├── ko/ # me_dma 内核驱动
│ ├── me_dma.c # 驱动源码
│ └── README.md # 驱动说明
├── test/test_dma.c # 测试用例
├── CMakeLists.txt # 构建配置
└── README.md # 模块说明
2. 环境准备
前置条件
- 运行环境:Linux 内核(支持 DMA-HEAP)、CMake ≥ 3.16、gcc/clang 编译器
- 依赖与外部资源:
- 已加载
me_dma.ko内核驱动模块 - libshm 共享内存库(同目录
../shm) - 内核需支持 DMA-HEAP 和 DMA 引擎
- 已加载
- 环境变量与初始化:若通过 SDK 编译,需先执行
source build/envsetup.sh并lunch <target> - 硬件与连接:目标板需支持 DMA 引擎,确认
/dev/me_dma设备节点存在 - 工具与权限:加载内核驱动需 root 权限(
insmod)
构建编译
- 获取代码:代码位于 SDK 的
components/system/dma目录 - 本模块编译:
独立编译方式:
cd components/system/dma
mkdir build && cd build
cmake ..
cmake --build .
通过 SDK mm 编译:
source build/envsetup.sh
lunch <target>
cd components/system/dma
mm clean && mm -v
- 产物:
- 用户态库:
libdma.so或libdma.a - 内核驱动:
dma/ko/build/output/me_dma.ko - 测试程序:
build/output/test_dma
- 用户态库:
3. 示例使用(从 0 跑通)
本节为读者按步骤复现的主线:命令可复制、路径写绝对或写明工作目录、每步给出预期现象(终端输出片段、退出码、界面或日志关键字)。
3.1 基本 DMA 拷贝测试
前置:已编译 libdma 和 me_dma.ko,目标板已上电并可通过串口或 SSH 访问
步骤 1:加载内核驱动
cd components/system/dma/ko/build/output
sudo insmod me_dma.ko
预期现象:执行 lsmod | grep me_dma 可看到模块已加载,ls /dev/me_dma 设备节点存在
步骤 2:运行测试程序
cd components/system/dma/build/output
./test_dma --help
预期现象:显示测试程序帮助信息,列出可用的测试选项
步骤 3:执行同步拷贝测试
./test_dma
预期现象:终端输出类似以下内容,显示 DMA 拷贝成功并验证数据正确性:
[INFO] DMA channel requested successfully
[INFO] Sync transfer: 4096 bytes
[INFO] Transfer completed, verifying data...
[INFO] Data verification passed
[TEST] PASSED
3.2 异步 DMA 传输示例
前置:见 §2
步骤 1:编写异步传输测试代码(参考 test/test_dma.c 中的异步示例)
步骤 2:提交异步传输任务
./test_dma --async
预期现象:程序提交 DMA 任务后立即返回,后台完成传输,输出显示传输 ID 和完成状态
步骤 3:等待传输完成
预期现象:程序调用 dma_wait() 等待传输完成,输出显示传输耗时和验证结果
4. 应用开发
-
对外 API 或接口形态:
- 头文件:
include/dma.h - 库名:
libdma.so或libdma.a - 主要 API:
dma_request_channel()- 请求 DMA 通道dma_release_channel()- 释放 DMA 通道dma_submit()- 提交异步传输任务dma_transfer_sync()- 执行同步传输dma_wait()- 等待异步传输完成dma_stop()- 停止传输
- 头文件:
-
调用方式与注意点:
- 线程安全:单个
dma_chan不支持多线程并发调用,需上层加锁或每线程独立通道 - 权限:需确保
/dev/me_dma设备节点可访问(通常需 root 或加入对应用户组) - 资源释放:使用完毕后必须调用
dma_release_channel()释放通道 - 内存对齐:传输地址和长度建议按 DMA 引擎要求对齐(通常 4 字节或 8 字节)
- 与 shm 配合:传输
shm_buffer时,需确保 buffer 已正确分配且未被释放
- 线程安全:单个
-
参考 demo 或示例路径:
components/system/dma/test/test_dma.c
5. 调试指南
- 内核日志查看:
dmesg | grep me_dma可查看驱动加载和传输错误信息 - 用户态日志:可在代码中添加
printf或使用strace跟踪系统调用 - 常见调试步骤:
- 确认驱动已加载:
lsmod | grep me_dma - 确认设备节点存在:
ls -l /dev/me_dma - 检查权限:
sudo chmod 666 /dev/me_dma(测试用) - 使用
strace ./test_dma查看系统调用失败原因
- 确认驱动已加载:
- 与硬件/内核同事分工时的信息收集清单:
- 内核版本和配置(
uname -a,cat /proc/config.gz | gunzip | grep DMA) - DMA 引擎类型和通道数
- 传输失败时的 dmesg 日志
- 传输参数(源地址、目标地址、长度、方向)
- 内核版本和配置(
6. 常见问题
| 现象 | 可能原因 | 处理 |
|---|---|---|
insmod me_dma.ko 失败 | 内核未启用 DMA-HEAP 或 DMA 引擎不支持 | 检查内核配置,确认硬件支持 |
/dev/me_dma 不存在 | 驱动未加载或加载失败 | 执行 dmesg 查看驱动加载日志 |
dma_request_channel() 返回 NULL | 设备节点权限不足或驱动未就绪 | 检查权限,确认驱动已加载 |
| 传输数据校验失败 | 地址未对齐或 cache 同步问题 | 确保地址对齐,使用 shm 的 cache sync API |
| 异步传输超时 | DMA 引擎繁忙或硬件故障 | 检查 dmesg 日志,确认硬件状态 |
附录:性能与测试数据
| 指标 | 数值 | 测试条件 |
|---|---|---|
| 内存拷贝带宽 | ~1.5 GB/s | 4MB 连续传输,MEM_TO_MEM 模式 |
| 同步传输延迟 | ~50 μs | 4KB 小块传输 |
| 异步传输吞吐 | ~1.8 GB/s | 多任务并发提交 |
测试方法:使用 test_dma 程序在目标板上测试,硬件平台为 SPACEMIT K1 芯片,Linux 内核 5.10,单线程顺序传输,统计 100 次平均值。测试命令:
./test_dma --benchmark --size 4194304 --iterations 100