zynq操作系统:Linux驱动开发AXIDMA补充篇 多路DMA

简介: Linux驱动开发AXIDMA补充篇 多路DMA

上一篇的一路双通道DMA的正常收发已经成功实现了,但是实际使用的时候大概率会挂载多路dma,那么我们调用的这个模块能不能支持多路的dma便是第一个要解决的问题

 首先阅读初始化部分的代码,自然有了第一个猜测,增加多路设备时,在dev目录是否可以生成多个axidma设备?即使不可以,可不可以通过修改解析设备树的部分代码,编写四个模块加载四次呢?(最后没有选择,找到了更简单合适的办法,这个理论上应该也可以吧)

 dmesg模块加载的信息,发现一行打印,说加载成功了一个收通道一个发送通道,如果只有一个设备的话,而且1明显是个变量打印,会不会增加不同设备后会多出通道,然后通过不同的通道ID来进行选择呢?!,第二个猜测感觉更为简单方便,而且从模块开发者的角度考虑,更加符合实际习惯

 开始对设备树通过引用覆盖的方式进行修改,首先就是在原来的基础上要增加节点,新增至四路,并确保每个通道id唯一

&axi_dma_0 {
  dma-channel@40400000 {
  xlnx,device-id = <0x0>;
  };
  dma-channel@40400030 {
  xlnx,device-id = <0x1>;
  };
};
&axi_dma_1 {
  dma-channel@40410000 {
  xlnx,device-id = <0x2>;
  };
  dma-channel@40410030 {
  xlnx,device-id = <0x3>;
  };
};
&axi_dma_2 {
  dma-channel@40420000 {
  xlnx,device-id = <0x4>;
  };
  dma-channel@40420030 {
  xlnx,device-id = <0x5>;
  };
};
&axi_dma_3 {
  dma-channel@40430000 {
  xlnx,device-id = <0x6>;
  };
  dma-channel@40400030 {
  xlnx,device-id = <0x7>;
  };
};

 剩下的dmas和dma-names部分一头雾水,仅仅这样很明显是不可能的,但是目前国内博客里找见的资料来看没有对多路axidma的说明,我们只能找到github源工程,找到readme阅读下对于设备树部分的描述,大致翻译如下:

Device Tree

 驱动程序需要设备树中的一个节点。此节点描述驱动程序具有独占访问权的DMA通道。它还用于探测驱动程序,因此仅在存在该节点时才激活驱动程序。该节点具有以下属性:

 compatible-这必须是字符串“ xlnx,axidma-chrdev”。这用于使驱动程序与设备树节点匹配。

 dmas -Xilinx AXI DMA或VDMA设备树节点的句柄列表(对其他设备树节点的引用),后跟0或1。这是指Xilinx AXI DMA / VDMA设备树节点内部的子节点,0表示当然是第一个子节点。

 dma-names-DMA通道的名称列表。名称可以完全任意,但必须唯一。DMA接口功能需要此功能dma_request_slave_channel(),否则驱动程序将不使用此功能。将来,驱动程序将在打印的消息中使用这些名称。

 对于Xilinx AXI DMA / VDMA设备树节点,唯一的要求是该device-id属性是唯一的,但它们可以完全是任意的。这是在驱动程序中以及从用户空间中引用通道的方式。有关创建AXI DMA / VDMA设备树节点的更多信息,请查阅内核文档。

 这是一个具有发送和接收通道的具有单个AXI DMA IP的系统的设备树节点的简单示例。注意,您将需要针对您的内核树和设置进行调整:

axidma_chrdev: axidma_chrdev@0 {
    compatible = "xlnx,axidma-chrdev";
    dmas = <&axi_dma_0 0 &axi_dma_0 1>;
    dma-names = "tx_channel", "rx_channel";
};
axi_dma_0: axidma0@40400000 {
    #dma-cells = <1>;
    compatible = "xlnx,axi-dma", "xlnx,axi-dma-6.03.a", "xlnx,axi-dma-1.00.a";
    reg = <0x40400000 0x10000>;
    clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>, <&clkc 15>;
    clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";    
    xlnx,include-sg;    
    xlnx,addrwidth = <32>;
    dma-mm2s-channel@40400000 {
        compatible = "xlnx,axi-dma-mm2s-channel";
        dma-channels = <1>;
        xlnx,datawidth = <64>;
        xlnx,device-id = <0>;
        interrupt-parent = <&intc>;
        interrupts = <0 29 4>;
    };
    dma-s2mm-channel@40400000 {
        compatible = "xlnx,axi-dma-s2mm-channel";
        dma-channels = <1>;
        xlnx,datawidth = <64>;
        xlnx,device-id = <1>;
        interrupt-parent = <&intc>;
        interrupts = <0 30 4>;
    };
};

 好像还是有点云里雾里,偶然间,在关闭的问题里找见了Problem with two dma in design!,

 源地址如下:https://github.com/bperez77/xilinx_axidma/issues/98

 楼主提出了挂载2个设备找不到通道的问题,不过很可惜,是因为平台不同导致的,ultrascale是64位的平台,而我所用的7045是32位的,楼主仅仅对datawidth做了更改后就解决了问题,不过收获还是很明显的,在楼主和遇见类似问题(我就不信没人用多个dma)的讨论中,我看到了这样的一张图:

@honorpeter it seems like you have succeeded someway but i have no idea how this kind message showed up
45.547129] axidma:axidma dma.c:axidma dma init:719:DMA:Found2 transmit channels and 2 receive channels.45.557138] axidma:axidmadma.c:axidma dma_init:721:VDMA:Found 0 transmit channels and o receive channels. root@pynq:~/DMA_Loop_cache/memory#

 一下确定了我的第二个猜想,继续阅读评论,在楼主没解决问题的时候,有软件工程师提出了这样的修改建议

What if you try to set in pl.dtsi something like this:
amba_pl:amba_pl@@ {
....
axidma chrdev:axidma chrdev@0 {
compatible = "xlnx,axidma-chrdev";
dmas=<&ps2p1a&pl2ps1>; // note to the 1 after pl2ps, it is the xlnx,device-id
};  dma-names = "tx channel", "rx channel"; Hx--1024

 楼主虽然两个dma,但是很明显应该只用一个方向的通道,一个用来PL发向PS,一个PS发给PL,观察这里对dmas的注释,提到了0和1是设备号,难道是我们新加的通道唯一的编号吗,(在之前只有一个是刚好发通道编号0收通道编号1),不论是模块编写者还是问题建议者在这块的描述都会导致我理解上有歧义,挨个试呗,所幸在我将0和1改成2和3后及时的报了加载失败的错误,终于明白该怎么办了(只能是0和1!!!)如果只用一个通道的话就是下面这种情况了

@suikammd And there is something wrong with your axidma chrdev dmas =<&pl2ps 0 &ps2pl 1>;
ifyou use two dma with only one channel both value should be 0
dmas=<&pl2ps 0 &ps2pl e>;
Andt seems like you set the dma-names in opposite if your desiqn is to send data from ps ddr to pl ddr
A list of phandles (references to other device tree nodes) of Xilinx AXI DMA or VDMA device tree nodes, followed by either 0 or 1. This refers to the child node inside of the Xilinx AXI DMA/VDMA device tree node, 0 of course being the first child node.

 而dma-names就很好理解了,因为每个通道都应该是独一无二的,那么起名字也应该对其区分,那么完整的修改就出来了

/include/ "system-conf.dtsi"
/ {
};
&amba_pl {
  axidma_chrdev: axidma_chrdev@0 {
  compatible = "xlnx,axidma-chrdev";
  dmas = <&axi_dma_0 0 &axi_dma_0 1 &axi_dma_1 0 &axi_dma_1 1 &axi_dma_2 0 &axi_dma_2 1 &axi_dma_3 0 &axi_dma_3 1 >;
  dma-names = "tx_channel", "rx_channel", "tx_channel1", "rx_channel1", "tx_channel2", "rx_channel2", "tx_channel3", "rx_channel3";
  };
};
&axi_dma_0 {
  dma-channel@40400000 {
  xlnx,device-id = <0x0>;
  };
  dma-channel@40400030 {
  xlnx,device-id = <0x1>;
  };
};
&axi_dma_1 {
  dma-channel@40410000 {
  xlnx,device-id = <0x2>;
  };
  dma-channel@40410030 {
  xlnx,device-id = <0x3>;
  };
};
&axi_dma_2 {
  dma-channel@40420000 {
  xlnx,device-id = <0x4>;
  };
  dma-channel@40420030 {
  xlnx,device-id = <0x5>;
  };
};
&axi_dma_3 {
  dma-channel@40430000 {
  xlnx,device-id = <0x6>;
  };
  dma-channel@40400030 {
  xlnx,device-id = <0x7>;
  };
};

 这总没有问题了吧!

 但是很明显没有这么顺利

xidma:axidma of.c:axidma of parse channel: 92: Device tree node dma: DMA has more than two channel nodes. xidma:probe of amba pl:axidma chrdev00 failed with error -38

 DMA超过两个节点了!难道模块仅仅支持两个dma设备吗

 先减少至两个试试

 果然我也出现了识别到两个发通道和两个收通道的好消息

axidma:axidma_dma.c:axidma_dma_init:718:DMA:Found 2 transmit channels and 2 receive channels. axidma:axidma_dma.c:axidma_dma_init:720:VDMA:Found 0 transmit channels and 0 receive channels.

 难道还要回到第一种猜想?

 所幸,模块开发者对于错误打印的编写做的太棒了,都不用复制错误信息grep,直接找到提示的c文件,函数,92行就找到了错误打印的源头,

80  static int axidma_of_parse_channel(struct device node *dma_node, int channel, 
81  struct axidma chan *chan, struct axidma device *dev)  
82  { 
83  int rc; 
84  struct device node *dma chan_node;  
85  u32 channel id; 
86
87  // Verify that the DMA node has two channel (child) nodes, one for Tx and rx  
88  if (of get child count(dma node) < 1) { 
89  axidma node_err(dma node, "DMA does not have any channel nodes.\n");  
90  return -EINVAL; 
91  } else if (of get child count(dma node) > 2) {  
92  axidma node err(dma node, "DMA has more than two channel nodes.\n");  
93  return -EINVAL; 
94  95  Hx--1024

 既然限制了不超过两个,我先强行改成4个试试,或许是参数的保护呢?(我不相信有开发者会在支持多设备时仅仅局限于 多=2)

axidma: axidma_dma.c:axidma_dma_init:718:DMA:Found 4transmit channels and 4 receive channels.
dm  dm  750.  VDMA.

剩下的就顺理成章接着调试了!



相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
相关文章
|
16天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
43 1
|
16天前
|
安全 前端开发 Android开发
探索移动应用与系统:从开发到操作系统的深度解析
在数字化时代的浪潮中,移动应用和操作系统成为了我们日常生活的重要组成部分。本文将深入探讨移动应用的开发流程、关键技术和最佳实践,同时分析移动操作系统的核心功能、架构和安全性。通过实际案例和代码示例,我们将揭示如何构建高效、安全且用户友好的移动应用,并理解不同操作系统之间的差异及其对应用开发的影响。无论你是开发者还是对移动技术感兴趣的读者,这篇文章都将为你提供宝贵的见解和知识。
|
17天前
|
安全 Linux 数据安全/隐私保护
深入Linux操作系统:文件系统和权限管理
在数字世界的海洋中,操作系统是连接用户与硬件的桥梁,而Linux作为其中的佼佼者,其文件系统和权限管理则是这座桥梁上不可或缺的结构。本文将带你探索Linux的文件系统结构,理解文件权限的重要性,并通过实际案例揭示如何有效地管理和控制这些权限。我们将一起航行在Linux的命令行海洋中,解锁文件系统的奥秘,并学习如何保护你的数据免受不必要的访问。
|
18天前
|
搜索推荐 Linux
深入理解Linux操作系统的启动过程
本文旨在揭示Linux操作系统从开机到完全启动的神秘面纱,通过逐步解析BIOS、引导加载程序、内核初始化等关键步骤,帮助读者建立对Linux启动流程的清晰认识。我们将探讨如何自定义和优化这一过程,以实现更高效、更稳定的系统运行。
|
16天前
|
存储 缓存 网络协议
Linux操作系统的内核优化与性能调优####
本文深入探讨了Linux操作系统内核的优化策略与性能调优方法,旨在为系统管理员和高级用户提供一套实用的指南。通过分析内核参数调整、文件系统选择、内存管理及网络配置等关键方面,本文揭示了如何有效提升Linux系统的稳定性和运行效率。不同于常规摘要仅概述内容的做法,本摘要直接指出文章的核心价值——提供具体可行的优化措施,助力读者实现系统性能的飞跃。 ####
|
17天前
|
人工智能 搜索推荐 Android开发
移动应用与系统:探索开发趋势与操作系统演进####
本文深入剖析了移动应用开发的最新趋势与移动操作系统的演进历程,揭示了技术创新如何不断推动移动互联网生态的变革。通过对比分析不同操作系统的特性及其对应用开发的影响,本文旨在为开发者提供洞察未来技术方向的视角,同时探讨在多样化操作系统环境中实现高效开发的策略。 ####
18 0
|
17天前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
19天前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
21天前
|
消息中间件 安全 Linux
深入探索Linux操作系统的内核机制
本文旨在为读者提供一个关于Linux操作系统内核机制的全面解析。通过探讨Linux内核的设计哲学、核心组件、以及其如何高效地管理硬件资源和系统操作,本文揭示了Linux之所以成为众多开发者和组织首选操作系统的原因。不同于常规摘要,此处我们不涉及具体代码或技术细节,而是从宏观的角度审视Linux内核的架构和功能,为对Linux感兴趣的读者提供一个高层次的理解框架。
|
23天前
|
人工智能 安全 Linux
Linux操作系统的演变与未来趋势###
本文深入探讨了Linux操作系统从诞生至今的发展历程,分析了其开源模式对技术创新和IT行业的影响,并展望了Linux在未来技术生态中的角色。通过历史回顾、现状分析和未来预测,本文旨在为读者提供一个关于Linux操作系统全面而深入的视角。 ###
下一篇
DataWorks