petalinux axidma驱动构建
- 1. 内核级别的dma driver与内建测试
- 2. DMA From User Space
- 3. Xilinx AXI DMA Driver and Library
- 4. 其他问题
- 4.1. xilinx_dmatest: No Tx channel
- 4.2. dstbuf[xxx] not copied! Expected aa, got bb
- 4.3. axi_dma.c:97:34: error: array type has incomplete element type ‘struct of_device_id’
- 4.4. axidma: axidma_dma.c: axidma_request_channels: 649: Unable to get slave channel 0: tx_channel
- 4.5. axidma: axidma_dma.c: axidma_prep_transfer: 236: Unable to prepare the dma engine for the DMA transmit buffer
- 调用 int axidma_oneway_transfer(axidma_dev_t dev, int channel, void buf, size_t len, bool wait) 函数报 timed out 问题
- 5. 其他参考
1. 内核级别的dma driver与内建测试
1.1. 硬件配置
搭建一个简单的DMA回环通路。(我不能确定回环之间放置FIFO是否会导致问题,按理来说应该不会)
参考Zynq UltraScale+ PL Masters,Wiki指出了一些ZynqMP在配置PL端master总线时需要注意的问题。
1.1.1. ZyqnMP配置
直接应用block automation,其他什么也不用动。
参考MPSoC configuration GUI what is "Address Fragmentation High Address?",自2018.3后不需要手动配置启用高地址,已默认启用。
1.1.2. dma配置
- 注意要启用Scatter Gather Engines,尽管Xilinx提到自己的驱动支持Simple Mode,但其内建测试无法再Simple Mode下工作。
- 注意要将BufferLength拉满。
启用axi_dma_0的DDR_HIGH地址,注意要同时启用OCM否则无法正常分配地址。
Data_SG里有一个地址默认没有启用,因为SG是后来加的,我也不确定启用是否会出问题。
1.2. 软件配置
1.2.1. Kernel设置
petalinux-config -c kernel
打开GUI,进入Device Drivers > DMA Engine support > Xilinx DMA Engines
,正常情况下,Xilinx DPDMA Engine正常勾选,然后将DMA Test Client for AXI DMA设置为module。记得保存为默认名.config
,否则可能编辑无效。
可以通过再召唤GUI进行确认
1.2.2. 用户设备树编辑
打开system-user.dtsi
(参考W03第1.5节:设备树),加入以下修改:
/ {
axidmatest_0: axidmatest@0 {
compatible ="xlnx,axi-dma-test-1.00.a";
dmas = <&axi_dma_0 0
&axi_dma_0 1>;
dma-names = "axidma0", "axidma1";
};
};
dmas那里需要填入正确的名字,参见pl.dtsi
,下面显示dma叫axi_dma_0,也与block design中的对应。
/ {
amba_pl: amba_pl@0 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges ;
axi_dma_0: dma@a0000000 {
#dma-cells = <1>;
clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";
clocks = <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>;
compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";
interrupt-names = "mm2s_introut", "s2mm_introut";
interrupt-parent = <&gic>;
interrupts = <0 89 4 0 90 4>;
reg = <0x0 0xa0000000 0x0 0x10000>;
xlnx,addrwidth = <0x40>;
xlnx,include-sg ;
xlnx,sg-length-width = <0x1a>;
dma-channel@a0000000 {
compatible = "xlnx,axi-dma-mm2s-channel";
dma-channels = <0x1>;
interrupts = <0 89 4>;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x0>;
};
dma-channel@a0000030 {
compatible = "xlnx,axi-dma-s2mm-channel";
dma-channels = <0x1>;
interrupts = <0 90 4>;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x0>;
};
};
};
};
1.3. 上板测试
$ modprobe axidmatest
[ xxx ] dmatest: Started 1 threads using dma1chan0 dma1chan1
[ xxx ] dma1chan0-dma1c: terminating after 5 tests, 0 failures 3897 iops 22603 KB/s (status 0)
说明回环测试通过。
2. DMA From User Space
本章内容可能已被放弃,第3章可能是其更好的替代
理论参考
- wiki: DMA From User Space
- wiki: DMA From User Space 2.0
- github源码: Xilinx-Wiki-Projects/software-prototypes
这一套东西的问题在于,太他妈抽象了,完全不知道怎么用,可能github的源码需要编译module,我还没有研究,暂时搁置这个方案。
设计参考:
- AXI DMA Linux user space application on Zynq MPSoC platform:这个程序会直接报Segmentation Fault然后崩溃。
- 70413 - Zynq UltraScale+ MPSoC Example Design: Using 64-bit addressing with AXI DMA:附件代码编译不通过,报错缺少
xaxidma.h
不知道怎么解决,我认为这可能不是给petalinux用的。 - 更多相关:在Xilinx Support搜索Linux DMA from user space
3. Xilinx AXI DMA Driver and Library
参考:
- bperez77/xilinx_axidma:github库
- ZYNQ系列(十二)linux的DMA使用:中文的流程,缝百家之长
3.1. 修改用户设备树
&amba_pl {
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{
dma-channel@a0000000 {
xlnx,device-id = <0x0>;
};
dma-channel@a0000030 {
xlnx,device-id = <0x1>;
};
};
3.2. 编译
在这里编译采用编辑config.mk
文件的方法,这里我们启用交叉编译,并指定zcu106对应的架构:
# Cross Compilation Options
CROSS_COMPILE = aarch64-linux-gnu-
ARCH = arm64
# Build Options
KBUILD_DIR = /home/megumism/xilinx-zcu106-2019.2/build/tmp/work/zcu106_zynqmp-xilinx-linux/linux-xlnx/4.19-xilinx-v2019.2+git999-r0/linux-xlnx-4.19-xilinx-v2019.2+git999
OUTPUT_DIR = outputs
接下来只需要
make driver
make examples
3.3. 程序上板
将./output
文件夹中的东西一并拷贝到sdcard中,在运行任何程序前需要先加载驱动:
$ insmod axidma.ko
axidma: axidma_dma.c: 672: DMA: Found 1 transmit channels and 1 receive channels.
axidma: axidma_dma.c: 674: VDMA: Found 0 transmit channels and 0 receive channels.
说明驱动正常。
3.4. 将output文件夹
4. 其他问题
4.1. xilinx_dmatest: No Tx channel
考虑两种情况:
- 硬件配置有问题,驱动没能检测到硬件。这在我第一次建立完bd之后(那时没有使用
axidma.ko
)调试了很久无果,后来重新建了一次bd,遂解决。 - 通道被其他设备占用,例如当启用
axidma.ko
的时候,dmatest
就无法接触到dma端口。考虑rmmod
。
4.2. dstbuf[xxx] not copied! Expected aa, got bb
参考Linux AXI DMA test error on Zynq zc706 board
打开dma的Scatter Gather Engine
4.3. axi_dma.c:97:34: error: array type has incomplete element type ‘struct of_device_id’
参考Can not build petalinux module #123中 lordlothard commented on 12 May 2021 一楼给出的解决方案:
- add
"#include <linux/of_address.h>"
into driver/axi_dma.c - in axidma_chrdev.c, change the parameter from
of_dma_configure(dev->device, NULL,) ;
toof_dma_configure(dev->device, NULL, true) ;
4.4. axidma: axidma_dma.c: axidma_request_channels: 649: Unable to get slave channel 0: tx_channel
- 参考Not finding tx_channel in device tree #47:通道被其他设备占用,例如当启用
dmatest
的时候,axidma.ko
就无法接触到dma端口。考虑rmmod
- 参考Problem with two dma in design #98,rx channel探测不到可能是地址没有设置为>=40位
- 最后考虑DMA的中断是否正确连接到ZynqMP上
4.5. axidma: axidma_dma.c: axidma_prep_transfer: 236: Unable to prepare the dma engine for the DMA transmit buffer
参考Unable to prepare the dma engine for the DMA transmit buffer. #85
将DMA的"Width of Buffer Length Register"拉满(26)。
调用 int axidma_oneway_transfer(axidma_dev_t dev, int channel, void buf, size_t len, bool wait) 函数报 timed out 问题
5. 其他参考
- Introduction to Using AXI DMA in Embedded Linux:外国人在Arty Z7上跑的,附有代码但没有细看。
- ZYNQ跑系统 系列(四) AXI-DMA的linux下运行:与ZYNQ系列(十二)linux的DMA使用大同小异。
- ZYNQ Linux 应用层 利用 AXI DMA 进行数据传输:附有错误说明。