上一篇的一路双通道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.
剩下的就顺理成章接着调试了!