ZynqMP平台Linux系统下AXI DMA的BD环强制分配至PL RAM的技术问询
你的核心问题在于Xilinx AXI DMA驱动默认未从你预留的PL RAM区域分配Buffer Descriptor(BD)环,导致BD位于系统内存,而DMA硬件仅能访问PL RAM,最终造成传输停滞。以下是分步解决方法:
1. 修正预留内存区域的设备树配置
你当前的pl_dma_pool节点设置了no-map属性,这会阻止内核为该区域创建虚拟地址映射,但Xilinx DMA驱动需要访问BD的虚拟地址来管理描述符,因此该属性会迫使驱动 fallback 到系统内存分配BD。
修改reserved-memory节点如下:
reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; pl_dma_pool: dma_pool@400000000 { compatible = "shared-dma-pool"; reg = <0x00000004 0x00000000 0x00000000 0x80000000>; reusable; alignment = <0x1000>; // 对齐到BD所需的4KB粒度 size = <0x80000000>; }; };
同时删除多余的reserved-mem@400000000节点,避免配置冲突。
2. 确认AXI DMA节点与预留内存的关联
你已经在axi_dma_0及其s2mm通道节点添加了memory-region = <&pl_dma_pool>,这一步是正确的。Xilinx DMA驱动会优先使用设备关联的memory-region进行分配,前提是该区域没有no-map限制。
3. 验证BD环的分配地址
修改设备树后重新编译烧录镜像,启动后可通过以下方式验证BD是否落在PL RAM范围内:
- 开启内核DEBUG_FS后,查看
/sys/kernel/debug/dmaengine/<dma-channel>/下的BD地址信息 - 在驱动中添加打印,输出BD环的物理地址,确认是否处于
0x400000000 - 0x47FFFFFFF区间
4. (可选)修改Xilinx DMA驱动强制从预留内存分配BD
若上述步骤后BD仍未分配到PL RAM,需修改Xilinx DMA驱动代码(drivers/dma/xilinx/xilinx_dma.c),在xilinx_dma_alloc_bd_ring函数中显式使用设备的预留内存区域:
struct device *dev = chan->device->dev; struct reserved_mem *rmem = dev_get_dma_reserved_mem(dev); if (rmem) { // 从预留内存分配BD环,需自行管理偏移避免冲突 static u64 bd_offset = 0; bd_ring->virt = devm_memremap(dev, rmem->base + bd_offset, size, MEMREMAP_WB); bd_ring->phys = rmem->base + bd_offset; bd_offset += size; } else { // 回退到默认分配方式 bd_ring->virt = dma_alloc_coherent(dev, size, &bd_ring->phys, GFP_KERNEL); }
5. 优化自定义驱动的SG列表处理
你的自定义驱动中手动设置sg_dma_address和sg_dma_len是可行的,但更推荐使用dma_map_sg自动处理,避免手动设置的潜在错误:
int sg_len = dma_map_sg(adev->s2mm->dma_channel->device->dev, adev->s2mm->sglist, BD_CNT, DMA_DEV_TO_MEM); if (sg_len != BD_CNT) { pr_err("Failed to map SG list\n"); return -EINVAL; }
完成上述修改后,重新编译内核和设备树,烧录后BD环的物理地址应落在PL RAM范围内,传输中断也能正常触发。
内容的提问来源于stack exchange,提问作者Дмитрий Кортиков




