双Zynq MPSoC PS侧PCIe高速DMA互连

引言

在涉及Xilinx Zynq UltraScale+ MPSoC的项目中,实现设备间高速、低延迟的数据传输往往是核心需求之一。PCIe(尤其PS侧)结合DMA(直接内存访问)正是满足这类需求的理想技术方案。

在近期支持的客户项目中,其核心需求在于:在一款PCB单板上,集成两颗Zynq MPSoC器件,并利用其PS侧的PCIe控制器,直接构建点对点DMA数据传输链路,从而避免引入额外的PCIe交换芯片。为了验证该方案的可行性并积累经验,我们使用两块ZCU102开发板成功搭建并测试了一个工作Demo。

这篇文章将聚焦这一实战过程,手把手带你完成:环境搭建、硬件配置、驱动移植、系统编译到最终的上板测试验证,目标是帮你快速在你的MPSoC项目上实现类似的高速DMA互连!

一、实战准备:软硬件环境搭建

1.1硬件准备

开发板:两块Xilinx ZCU102开发板。

连接线:一根PCIe公对公延长线缆。

角色分配

板卡1:配置为RC(Root Complex)。

板卡2:配置为EP(Endpoint)。

物理连接:将两块板的PS侧PCIe插槽通过延长线缆直接相连(如下图所示)。

ZCU102.jpg

1.2 软件准备

软件版本

Vivado:2021.2(用于硬件设计和比特流生成)。

PetaLinux:2021.2(用于嵌入式Linux系统构建)。

1.3 驱动准备

(Xilinx PCIe Root and EndPoint - Xilinx Wiki - Confluence[1])我们需对其进行交叉编译以生成适用于ARM64架构的内核模块(.ko)。

注:

[1] https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/85983409/Xilinx+PCIe+Root+and+EndPoint(复制到浏览器打开)

ZCU102-1.png

二、详细实现过程拆解

2.1 硬件设计(RC端配置-Vivado)

① 创建block design后,添加“Zynq Ultrascale+ MPSoC” IP。

② 运行Block automation,进行基础配置。

③ 注意将自动生成的“maxihpm0_fpd_aclk”和“maxihpm1_fpd_aclk”与“pl_clk0”连线,否则会导致后面validate不通过。

④ Vivado通常已自动分配管脚,默认模式为RC,使用GT Lane 0。在“IO Configuration”的页面可以看到,PCIE默认配置为Gen2 x1,其他GT Lane分别配置给DP/USB3.0/SATA。本实验使用默认配置。

ZCU102-2.png


⑤ PCIE高级配置,勾选“Switch To Advanced Mode”。

确保Class Code值设置为0x060400(代表PCI-to-PCI Bridge)。如果使用错误的类代码,Linux在枚举时可能导致BAR分配失败!其余高级配置一般可用默认值。

ZCU102-3.png

⑥ 配置完成后,按照“Generate Output Products” ->“Create HDL Wrapper”->“Generate Bitstream”的流程。成功生成比特流后,导出.xsa文件,用于PetaLinux系统构建。

2.2 构建Linux系统(RC端-Petalinux)

① petalinux工程创建

petalinux-create --type project -s xilinx-zcu102-v2021.2-final.bsp -n zcu102_rc

② 导入硬件描述(.xsa)

petalinux-config -- get-hw-description = (path of zcu102_rc.xsa)

③ 配置Linux内核

petalinux-config -c kernel

由于内核配置中默认开启了ps PCIe的DMA,为了避免后面安装外部驱动时冲突,这里需要去掉Xilinx PS PCIe DMA support的默认勾选。

ZCU102-4.png

④ 编译工程

petalinux-build

⑤ 打包文件

petalinux-package --boot --fsbl zynqMP_fsbl  --u-boot u-boot.elf --force

生成BOOT.BIN、image.ub、boot.scr等关键启动文件。将上述生成的启动文件复制到SD卡的boot分区。

2.3 编译移植PS PCIE DMA驱动(RC端)

① 获取并修改驱动源码:从Xilinx Wiki获取驱动源码。由于官方提供的驱动源码是在X86 host上编译执行的,还需要将其修改为可在ARM上执行的ko文件,即交叉编译。

② 修改Makefile,将KERNEL_DIR指定为本地内核代码所在路径。内核路径示例(请根据实际路径修改):

/home/your_user_name/petalinux_pro/peta_2021/zcu102_rc/build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.10+gitAUTOINC+568989d441-r0/linux-zynqmp_generic-standard-build。

③ 在驱动源码目录执行make命令,成功编译后会生成ps_PCIe_dma.ko内核模块文件。

④ 将编译生成的ko文件、apps路径下的simple_test应用文件以及petalinux打包好的Boot.bin、image.ub和boot.scr都拷贝至SD。

2.4 硬件准备(EP端)

① vivado配置(类似RC,但关键点不同)

a.在IO configuration中明确将PCIe模式设置为Endpoint。

b.关键修改,将Device ID修改为“0XA808”。此值必须与驱动源码中ZYNQMP_DMA_DEVID1定义的预期设备ID严格匹配,否则驱动无法正常运行。

ZCU102-5.png

② 生成并导出硬件设计。

③ 创建EP端Boot文件,在vitis中:基于导出的.xsa文件新建Vitis平台工程。创建一个简单的Hello World应用程序工程(仅用于加载运行基本固件)。将其复制到EP板SD卡。

2.5上板实测

① 上电启动:

将准备好的SD卡(含boot文件)分别插入两块ZCU102。

两块板均设置为SD卡启动模式。

连接RC板的串口到主机终端(如PuTTY或minicom)。

② EP枚举观察(RC串口输出):

给两块板上电。

在RC板的串口终端中,你应该能看到类似XXX:PCI host bridge /PCIe@fd0e0000 ranges:和XXX:PCIe:Link up的日志信息,这表明PCIe链路已成功建立并枚举到EP设备。

ZCU102-6.png

③ 加载驱动(RC端命令):

在RC板的Linux命令行中,进入存放驱动的目录。

执行:insmod ps_pcie_dma.ko

检查设备节点:成功加载后,/dev/PCIe(例如/dev/ps_pcie_epdma0)等设备节点应被创建。

ZCU102-7.png

④ 运行DMA测试程序(RC端命令):

执行命令进行传输测试(以下仅为示例命令,具体参数需看程序说明):./simple_test

ZCU102-8.png

⑤ 测试结果解读:

程序运行后,终端会打印传输的速度数据。

在我们的测试中(Gen2 x1链路):

RC -> EP(写入EP内存):传输4MB数据,平均速度约为372MB/s。

EP -> RC(写入RC内存):传输4MB数据,平均速度约为378MB/s。

本文详细展示了如何利用两块Xilinx Zynq UltraScale+ MPSoC ZCU102开发板,通过配置其PS侧PCIe控制器分别作为RC和EP,最终实现了两者之间基于DMA驱动的高速数据互传功能。该方案验证了在MPSoC设计中直接利用片上PCIe资源构建高速点对点链路的可行性。

三、资源分享

① GitHub - Xilinx/zynqmp-psPCIe-epdma

https://github.com/Xilinx/zynqmp-pspcie-epdma 

② Zynq UltraScale+ Device Technical Reference Manual(UG1085)•查看器•AMD技术信息门户网站

https://docs.amd.com/v/u/en-US/ug1085-zynq-ultrascale-trm 

文章来源:安富利