Linux DMA Engine 基础
1 DMA基础信息查看 /sys/class/dma
root:~# ls /sys/class/dma/
dma0chan0 dma1chan10 dma1chan27 dma2chan14 dma2chan30 dma2chan47 dma2chan63 dma3chan21 dma3chan38 dma3chan54
dma0chan1 dma1chan11 dma1chan28 dma2chan15 dma2chan31 dma2chan48 dma2chan7 dma3chan22 dma3chan39 dma3chan55
......
还可以查看特定通道信息:
root:~# ls /sys/class/dma/dma2chan1/
bytes_transferred device in_use memcpy_count power slave subsystem uevent
该命令查看有哪些可用的dma channel, 每个dma有多少个channel. 还可以,
查看特定channel是否在使用,下面这个就是在使用:
cat /sys/class/dma/dma2chan1/in_use
1
2 调试 DMA Engine /sys/kernel/debug/dmaengine
它通过 debugfs 文件系统提供了对 DMA 控制器、通道、传输状态等底层信息的访问,是开发者排查 DMA 相关问题时的重要工具。
2.1 目录结构与核心文件
root:~# ls /sys/kernel/debug/dmaengine/
42000000.dma-controller 42df0000.dma-controller 44000000.dma-controller 4b110000.epxp summary
虽然网上说的这个目录的调试用法天花乱坠,但是我发现只有summary有用:
root:~# cat /sys/kernel/debug/dmaengine/summary
dma0 (4b110000.epxp): number of channels: 16dma1 (44000000.dma-controller): number of channels: 32dma1chan0 | in-usedma1chan20 | 44380000.serial:txdma1chan21 | 44380000.serial:rxdma2 (42000000.dma-controller): number of channels: 64dma2chan0 | 42530000.i2c:tx (给出了具体分给哪个节点了)dma2chan1 | 42530000.i2c:rxdma3 (42df0000.dma-controller): number of channels: 64dma3chan0 | 42540000.i2c:txdma3chan1 | 42540000.i2c:rxdma3chan2 | 426c0000.i2c:txdma3chan3 | 426c0000.i2c:rx
可以发现,得到的信息包括:控制器名称,如44000000.dma-controller,总通道数 32、64,已经分配的通道分给哪个具体的节点了,还给出了通道对应的外设偏移地址 等。
3 看手册学习
linux-kernel$ ls Documentation/driver-api/dmaengine/
client.rst dmatest.rst index.rst provider.rst pxa_dma.rst
index.rst 就是个简单的摘要。
dmatest.rst 如何编译和使用dmatest工具来测试指定dma channel。
client.rst 如何使用DMAEngine的Slave-DMA API(仅适用slave DMA)。
provider.rst
3.1 dmatest.rst
文档说明dmatest工具怎么编译,如何使用来测试dma, 该工具只能测试memory to memory。
如何使用edma进行内存到内存测试echo 2000 > /sys/module/dmatest/parameters/timeout 单位是毫秒
echo 1 > /sys/module/dmatest/parameters/iterations
echo dma1chan0 > /sys/module/dmatest/parameters/channel //可以让多个通道同时测试
echo dma1chan1 > /sys/module/dmatest/parameters/channel
echo dma1chan2 > /sys/module/dmatest/parameters/channel
【注】此时通过 cat /sys/kernel/debug/dmaengine/summary 可以看哪些通道正在使用。
echo 1 > /sys/module/dmatest/parameters/run 为1时会启动传输,写0会释放通道
【注】可以通过cat /proc/interrupts | grep dma 查看对应的DMA channel是否发生中断。检查手段
ls /sys/class/dma/ 可以得到哪些cannel可用
echo "" > /sys/module/dmatest/parameters/channel 这样会将所有不忙的通道加入测试,我日了。
cat /sys/module/dmatest/parameters/run 查看run的状态
cat /sys/module/dmatest/parameters/channel 可用查看成功添加的channel
cat /sys/module/dmatest/parameters/test_list 会打印pending的test
echo 0 > /sys/module/dmatest/parameters/run 会释放通道。
dmesg | tail -n 1 查看位于kernel log的测试结果,会显示错误数量
3.2 provider.rst
对dmaengine框架做了介绍,DMAEngine APIs小节讲解内容比较重要。 Device operations 介绍了注册到dma_device structure的操作函数都是干嘛的,什么时候用。
3.3 client.rst
slave DMA 的使用包含的步骤:申请DMA slave channel, 设置参数,得到传输描述符,提交传输,等待回调。这篇文章讲解的很详细。
4 初识 DMA Engine
4.1 DMA controller 了解
DMA Engine是开发DMA控制器驱动程序的通用内核框架。DMA的主要目的是在复制内存的时候减轻CPU的负担。使用通道将事务(I/O数据传输)委托给DMA Engine,DMA Engine通过其驱动程序API提供一组可供其他设备(从设备)使用的通道.
Linux为了方便基于DMA的memcpy、memset等操作,在dma engine之上,封装了一层更为简洁的API,这些API就是Async TX API. 【参考博客】
因为 memory 到 memory 有了简洁的API,没必要直接使用 dma engine 提供的API了,所以把 dma engine 提供的API特指为 Slave-DMA API (slave指的是参与DMA传输的设备,比如IIC, UART等)
这篇博客介绍了如何依据DMA engine框架实现 dma controller driver 。
dma controller driver的核心实现如下:
- 定义一个struct dma_device变量,并根据实际的硬件情况,填充其中的关键字段(如device_alloc_chan_resources,device_free_chan_resources接口等)。
- 调用dma_async_device_register函数,将dma_device注册到dmaengine框架中。
4.2 如何使用 DMA engine 框架传输
对设备驱动的编写者来说,要基于dma engine提供的Slave-DMA API进行DMA传输的话,需要如下的操作步骤【参考博客】:
1)申请一个DMA channel。
2)根据设备(slave)的特性,配置DMA channel的参数。
3)要进行DMA传输的时候,获取一个用于识别本次传输(transaction)的描述符(descriptor)。
4)将本次传输(transaction)提交给dma engine并启动传输。
5)等待传输(transaction)结束。
4.3 代码示例
关键代码
struct dmatest_dev {struct cdev cdev; /* 字符设备结构 */
};
static struct dmatest_dev *dmatest_dev_all;
static dev_t devt; /* 用于存储设备号 */static int dmatest_major = DMATEST_MAJOR;
static int dmatest_minor = DMATEST_MINOR;
static int dmatest_nr_devs = 1; /* 设备数量 *///bus address 给DMA用
dma_addr_t dma_src;
dma_addr_t dma_dst;//virtual address 给驱动程序用
char *src = NULL;
char *dst = NULL ;struct dma_device *dev; //dma设备结构体
struct dma_chan *chan; //channel 结构体/*
* 申请主设备号,但需要自己用mknod的方式依据主设备号注册设备节点。
*/
static int dmatest_register_chrdev(void)
{int result; if (dmatest_major) {devt = MKDEV(dmatest_major, dmatest_minor);result = register_chrdev_region(devt, dmatest_nr_devs, DEVICE_NAME); //向内核注册设备号, 设备名称示在 /proc/devices} else {result = alloc_chrdev_region(&devt, dmatest_minor, dmatest_nr_devs, DEVICE_NAME);//向内核注册设备号, 设备名称示在 /proc/devicesdmatest_major = MAJOR(devt);}if (result < 0) {printk(KERN_WARNING "dmatest: can't get major %d\n", dmatest_major);}return result;
}/* 初始化module */
static int dmatest_init(void)
{int i, result;dma_cap_mask_t mask;result = dmatest_register_chrdev();//向内核申请主设备号printk(KERN_NOTICE "%s : get device major number %d\n", __func__, dmatest_major);dmatest_dev_all = kmalloc(dmatest_nr_devs * sizeof(struct dmatest_dev), GFP_KERNEL);for (i = 0; i < dmatest_nr_devs; i++)dmatest_setup_cdev(&dmatest_dev_all[i], i); //调用cdev_init,cdev_add实现字符设备注册dma_cap_zero(mask);dma_cap_set(DMA_MEMCPY, mask); //direction:memory to memorychan = dma_request_channel(mask, 0, NULL); //request a dma channelflags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;dev = chan->device;//alloc 512B src memory and dst memorysrc = dma_alloc_coherent(dev->dev, 512, &dma_src, GFP_KERNEL); //一致性dma映射,参数3为总线地址会给DMA用,返回值为内核虚拟地址驱动程序可用pr_info("src = %px, dma_src = %#llx\n",src, dma_src);dst = dma_alloc_coherent(dev->dev, 512, &dma_dst, GFP_KERNEL); //一致性dma映射,参数3为总线地址,给DMA用,返回值为内核虚拟地址驱动程序可用pr_info("dst = %px, dma_dst = %#llx\n",dst, dma_dst);for (i = 0; i < 512; i++){*(src + i) = (unsigned char)(i % 256); //启动传输前将源地址初始化}
...
}/* 卸载退出module */
static void dmatest_exit(void)
{int i;if (dmatest_dev_all) {for (i = 0; i < dmatest_nr_devs; i++) {cdev_del(&dmatest_dev_all[i].cdev);}kfree(dmatest_dev_all);}unregister_chrdev_region(devt, dmatest_nr_devs);//free memory and dma channeldma_free_coherent(dev->dev, 512, src, dma_src);dma_free_coherent(dev->dev, 512, dst, dma_dst);dma_release_channel(chan);
}
注册字符设备
//When dma transfer finished,this function will be called.
static void dma_callback_func(void * arg)
{int i;printk("Debug in %s() \n", __func__);for (i = 0; i < 10; i++){pr_info("%c",dst[i]); //打印EDMA传输结束后目的地址内容}
}static int dmatest_open(struct inode *inode, struct file *filp)
{return 0;
}
static int dmatest_release(struct inode *inode, struct file *filp)
{return 0;
}
static ssize_t dmatest_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{int ret = 0;//alloc a desc,and set dst_addr,src_addr,data_size.tx = dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, 512, flags);if (!tx){pr_info("Failed to prepare DMA memcpy \n");}/* 设置回调函数 */tx->callback = dma_callback_func;tx->callback_param = NULL;cookie = tx->tx_submit(tx); //submit the descif (dma_submit_error(cookie)){pr_info("Failed to do DMA tx_submit \n");}/* begin dma transfer */dma_async_issue_pending(chan);return ret;
}static ssize_t dmatest_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{int ret = 0;return ret;
}static const struct file_operations dmatest_fops = {.owner = THIS_MODULE,.read = dmatest_read,.write = dmatest_write,.open = dmatest_open,.release = dmatest_release,
};/** dmatest charter device registration*/
static void dmatest_setup_cdev(struct dmatest_dev *devt, int index)
{int err, devno = MKDEV(dmatest_major, dmatest_minor + index);cdev_init(&devt->cdev, &dmatest_fops);devt->cdev.owner = THIS_MODULE;devt->cdev.ops = &dmatest_fops;err = cdev_add(&devt->cdev, devno, 1);if (err)printk(KERN_NOTICE "Error %d adding dmatest%d", err, index);
}
编译成module后运行 mknod_edma.sh 依据设备号注册设备节点, 文件内容如下。
#!/bin/sh
module='edma_test_lyrix'
device='edma_test_lyrix'
mode='664'# 使用传入该脚本的i所有参数调用insmod,同时使用路径名来指定模块位置
/sbin/insmod ./$module.ko $* || exit 1# 删除原有节点
rm -f /dev/${device}[0-4]major=$(awk "\$2==\"$module\"{print \$1}" /proc/devices)mknod /dev/${device}0 c $major 0
最后在文件系统中使用 cat /dev/edma_test_lyrix0 触发DMA拷贝操作,然后可以看到模块打印,验证其目的地址内容与源地址内容相同了。
相关文章:
Linux DMA Engine 基础
1 DMA基础信息查看 /sys/class/dma root:~# ls /sys/class/dma/ dma0chan0 dma1chan10 dma1chan27 dma2chan14 dma2chan30 dma2chan47 dma2chan63 dma3chan21 dma3chan38 dma3chan54 dma0chan1 dma1chan11 dma1chan28 dma2chan15 dma2chan31 dma2chan48 dma2…...
【JavaEE】SpringMVC 请求传参
目录 一、请求二、传递单个参数三、传递多个参数四、传递对象五、RequestParam注解 后端参数重命名(后端参数映射)六、传递数组七、传递集合,RequestParam八、传递JSON数据8.1 JSON字符串和Java对象互转8.1.1 Test注解8.1.2 Java对象转JSON8.…...
观察者模式说明(C语言版本)
观察者模式主要是为了实现一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。下面使用C语言实现了一个具体的应用示例,有需要的可以参考…...
LeetCode 230.二叉搜索树中第K小的元素
题目:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。 思路: 代码: /*** Definition for a binary tree node.* public class Tre…...
11、集合框架
一、简介 Java集合框架位于java.util包中 Collection是Set和List的父类,Collections是工具类,提供了对集合进行排序、遍历等多种算法的实现。 ArrayList: 有序(放进去顺序和拿出来顺序一致),可重复 HashSet: 无序(放进去顺序和拿出来顺序不…...
git常用指令详解
文章目录 Git 基本指令的使用Git 远程仓库Git的分支管理 Git 基本指令的使用 git init //初始化一个git仓库,在当前目录下生成.git文件夹,并且会默认生成一个master分支。git clone <url> [directory] //url为git仓库地址,directory为本地目录 gi…...
Debezium 报错:“The db history topic is missing” 的处理方法
Debezium 报错:“The db history topic is missing” 的处理方法 一、引言 在使用 Debezium 进行数据同步时,可能会遇到一个常见的错误:“The db history topic is missing”。这个错误表明 Debezium 无法找到或访问其数据库历史记录主题(db history topic),这通常是由…...
Grok 3.0 Beta 版大语言模型评测
2025年2月17日至18日,全球首富埃隆马斯克(Elon Musk)携手其人工智能公司xAI,在美国重磅发布了Grok 3.0 Beta版。这款被誉为“迄今为止世界上最智能的语言模型”的AI,不仅集成了先进的“DeepSearch”搜索功能࿰…...
AcWing 3691:有向树形态 ← 卡特兰数 + 复旦大学考研机试题
【题目来源】 https://www.acwing.com/problem/content/3694/ 【题目描述】 求 N 个相同结点能够组成的二叉树的个数。 【输入格式】 一个整数 N。 【输出格式】 输出能组成的二叉树的个数。 【数据范围】 1≤N≤20 【输入样例】 3 【输出样例】 5 【算法分析】 ● 卡特…...
便携式动平衡仪Qt应用层详细设计方案(基于Qt Widgets)
便携式动平衡仪Qt应用层详细设计方案(基于Qt Widgets) 版本:1.0 日期:2023年10月 一、系统概述 1.1 功能需求 开机流程:长按电源键启动,全屏显示商标动画(快闪3~4次)。主界面&…...
SpringBoot源码解析(十一):准备应用上下文
SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args Sp…...
CSS 使用white-space属性换行
一、white-space属性的常见值 * 原本格式: 1、white-space:normal 默认值,空格和换行符会被忽略过滤掉;宽度不够时文本会自动换行 * 宽度足够时,normal 处理后的格式 * 宽度不够时, normal 处理后的格式 2、white-spa…...
论文笔记(七十二)Reward Centering(四)
Reward Centering(四) 文章概括摘要附录A 伪代码 文章概括 引用: article{naik2024reward,title{Reward Centering},author{Naik, Abhishek and Wan, Yi and Tomar, Manan and Sutton, Richard S},journal{arXiv preprint arXiv:2405.09999…...
Matlab——图像保存导出成好看的.pdf格式文件
点击图像的右上角,点击第一个保存按钮键。...
官方文档学习TArray容器
一.TArray中的元素相等 1.重载一下 元素中的 运算符,有时需要重载排序。接下来,我们将id 作为判断结构体的标识。 定义结构体 USTRUCT() struct FXGEqualStructInfo {GENERATED_USTRUCT_BODY() public:FXGEqualStructInfo(){};FXGEqualStructInfo(in…...
unxi-进程间通信
1.进程间通信实现方式 【1】同一主机 linux下通信方式: a.传统的进程间通信方式 管道 --- 进行数据传输的"管道" 无名管道 有名管道 信号 --- b.system v 进程间通信 (posix 进程间通信) 共享内存 (进程间…...
微型分组加密算法TEA、XTEA、XXTEA
微型分组加密算法TEA、XTEA、XXTEA TEA(Tiny Encryption Algorithm)算法是一种分组加密算法,由剑桥大学计算机实验室的David Wheeler和Roger Needham于1994年发明。TEA、XTEA、XXTEA算法采用64位的明文分组和128位的密钥。它使用Feistel…...
conda 基本命令
1、查询当前所有的环境 conda env list 2、创建虚拟环境 conda create -n 环境名 [pythonpython版本号] 其中[pythonpython版本号]可以不写 conda create -n test python3.12 我们输入conda env list看到我们的环境创建成功了,但是发现他是创建在我们默认的C盘的…...
详解 为什么 tcp 会出现 粘包 拆包 问题
TCP 会出现 粘包 和 拆包 问题,主要是因为 TCP 是 面向字节流 的协议,它不关心应用层发送的数据是否有边界,也不会自动分割或合并数据包。由于 TCP 的流控制和传输机制,数据可能在传输过程中被拆分成多个小的 TCP 包,或…...
Linus的基本命令
以下是一些常见的 Linux 命令: 一、文件和目录操作: - ls:列出目录中的文件和子目录,常用参数有 -a (显示所有文件,包括隐藏文件)、 -l (显示详细信息)、 -h ࿰…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
