跳到主要内容

系统服务 · 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.shlunch <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.solibdma.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.solibdma.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 跟踪系统调用
  • 常见调试步骤:
    1. 确认驱动已加载:lsmod | grep me_dma
    2. 确认设备节点存在:ls -l /dev/me_dma
    3. 检查权限:sudo chmod 666 /dev/me_dma(测试用)
    4. 使用 strace ./test_dma 查看系统调用失败原因
  • 与硬件/内核同事分工时的信息收集清单:
    • 内核版本和配置(uname -acat /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/s4MB 连续传输,MEM_TO_MEM 模式
同步传输延迟~50 μs4KB 小块传输
异步传输吞吐~1.8 GB/s多任务并发提交

测试方法:使用 test_dma 程序在目标板上测试,硬件平台为 SPACEMIT K1 芯片,Linux 内核 5.10,单线程顺序传输,统计 100 次平均值。测试命令:

./test_dma --benchmark --size 4194304 --iterations 100