手把手教你搭建PCIe DMA系统

最近想自己搭建一个PCIE DMA系统,验证一下最近所学。本设计全部采用xilinx的IP核,PCIE部分采用axi bridge for pcie gen3 subsystem。DMA系统使用前面学习过得AXI Central Memory Access(CDMA)。

关于CDMA可以参考我之前得一篇文章。

XAPP1171和AXI-CDMA使用仿真_xilinx cdma-CSDN博客

在学习初期,搞不懂如何去搭建一个DMA系统,搞不懂这些IP分别有什么作用,搞不懂里面复杂的地址分配问题。以及如何在驱动层次去控制我的这个系统。当然本方案暂时不考虑效率的问题。如下图所示就说使用axi_pcie搭建的一个DMA系统。系统的核心是axi bridge for pcie IP核。其次就是使用了xilinx的AXI Central Memory Access(CDMA)这个IP去完成数据的搬移。其实这部分类容并不复杂,重要的是大家都不想去花费时间去看xilinx提供的文档。为了能够理解我还是把需要参考的文档发在下面。前面部分是本次设计需要参考的部分文档。

pg194-axi-bridge-pcie-gen3-en-us-3.0.pdf

pg034-axi-cdma.pdf

xapp1171-pcie-central-dma-subsystem.pdf

Xilinx_Answer_65062_AXI_PCIe_Address_Mapping.pdf

ds820_axi_pcie.pdf

关于pcie的相关基础知识和架构,可以参考下面的文档。

pg054-7series-pcie.pdf

整体框图

整体思路如上图所示。我的思路是通过axi bridge for pcie gen3 subsystem IP核的M_AXI接口分成三路,一路去控制AXI Central Memory Access(CDMA)的寄存器,即(DMA控制器寄存器),一路预留bram空间,方便用户自己做寄存器解析。另外一路去控制axi bridge for pcie gen3 subsystem IP核的寄存器空间,这里面主要就是控制其中的AXI Base Address Translation Configuration用于对应AXI基地址转换配置寄存器(就是你DMA操作对应的内存地址)。

在看另外一路,通过对axi_cdma的配置,现在可以启动DMA操作了,关于CDMA就是一个数据搬运的过程,他可以将数据从A搬移到B,这点在前面的文章中已经介绍过了。本次设计只使用最基础的数据搬运,不涉及SG端口(SG端口支持描述符,如果将描述符通过预存机制写入FPGA可以增加DMA的执行效率,这是为什么呢?看完下面的类容你或许会理解)

看连接部分,CDMA的M_AXI部分通过AXI interconnect分为了两部分,一路连接缓存,一路连接axi bridge for pcie gen3 subsystem IP核的S_AXI端口。通过配置CDMA的寄存器空间,实现缓存和pcie之间的数据交换。

IP介绍

axi bridge for pcie gen3 subsystem

关于此IP,他完成了pcie和axi协议之间的转换。即对AXI的突发操作转换为通过pcie发送带数据的TLP包操作。

关于IP的特性在pg194-axi-bridge-pcie-gen3-en-us-3.0.pdf上的P5有相关介绍。

该IP支持最大512字节的有效载荷,支持通过内存映射AXI4接口访问PCIe地址空间,支持PCIe访问内存映射AXI4地址空间。即通过AXI总线读写可以直接转换成对PCIE地址空间的读写,对PCIE的地址空间读写直接转换成对AXI地址空间的读写。作为EP设备时支持6个32位基地址寄存器和3个64位基地址寄存器。

Xilinx有两个IP支持pcie axi bridge,一个就是AXI Bridge for PCI Express Gen3 Subsystem,另外一个是DMA/Bridge Subsystem for PCI Express in AXI Bridge mode即XDMA。

架构框图

关于AXI Bridge for PCI Express Gen3 Subsystem的架构。

从上图结构可以看出来。AXI Bridge for PCI Express Gen3 Subsystem支持三种AXI总线,S_AXI_CTL是对IP本身的寄存器空间的配置。S_AXI从桥处理来自AXI的读写请求,转换为PCIE的读写TLP。M_AXI作为主设备连接到AXI,处理PCIE生成的读写TLP。

关于上面部分的详细解释。

寄存器模块,S_AXI_CTL是配置IP的寄存器,其中最主要的地方是配置axi to pcie translation将AXI内存映射到PCIE地址空间。

从桥slave bridge,对从桥的写事务会根据配置的Max Payload Size(最大载荷尺寸)被转换为一个或多个MemWr TLP(传输层数据包),并传递给PCI Express集成模块。最多支持8个活跃的AXI写请求。当远端AXI主设备发起读事务时,从桥会捕获读地址及控制信号,生成MemRd请求TLP,并启动完成超时计时器。接收到完成TLP后,数据将返回给AXI主设备。最多支持8个活跃AXI读请求。

对于主桥master bridge,主桥处理来自PCI Express集成模块的MemWr和MemRd请求TLP,实现PCIe地址域到AXI4内存映射地址域的转换。每个MemWr请求TLP头部会生成AXI4总线地址和控制信号,并将数据传递给目标AXI4从设备。最多支持8个活跃的PCIe MemWr请求TLP。

Memory map

这里只列举几个重点得寄存器。

bridge register memory map

AXI Base Address Translation Configuration:AXI基地址转换配置寄存器

地址范围:0x208 - 0x234

offsetbitsregister
0x20831-0
AXIBAR2PCIEBAR_0U
0x20c31-0
AXIBAR2PCIEBAR_0L
0x21031-0
AXIBAR2PCIEBAR_1U

0x214

31-0
AXIBAR2PCIEBAR_1L
0x21831-0
AXIBAR2PCIEBAR_2U
0x21c31-0
AXIBAR2PCIEBAR_2L
0x22031-0AXIBAR2PCIEBAR_3U
...
0x23431-0
AXIBAR2PCIEBAR_5L

AXI基地址转换配置寄存器位定义。

bitsnamecore accessresult valuedescription
31-0
Lower Address
R/W
C_AXIBAR2PCIEBAR_0(31 to 0)
生成PCIe地址时--该值将被替换为AXI地址的「最低有效32位」。
31-0
Upper Address
R/W
if (C_AXIBAR2PCIEBAR_0 = 64 bits),
then reset value =
C_AXIBAR2PCIEBAR_0(63 to 32)
if (C_AXIBAR2PCIEBAR_0 = 32 bits),
then reset value = 0x00000000
生成PCIe地址时--该值将被替换为AXI地址的「最高有效32位」。
...

AXI transactions for pcie

AXI4 memory-mapped Transactions to AXI4-Stream pcie TLPs

AXI4 Memory-Mapped Transaction
AXI4-Stream PCIe TLPs
INCR Burst Read of AXIBAR
MemRd 32 (3DW)
INCR Burst Write to AXIBAR
MemWr 32 (3DW)
INCR Burst Read of AXIBAR
MemRd 64 (4DW)
INCR Burst Write to AXIBAR
MemWr 64 (4DW)

AXI4-Stream pcie TLPs to AXI4 memory-mapped Transactions

AXI4 Memory-Mapped Transaction
AXI4-Stream PCIe TLPs
MemRd 32 (3DW) of PcieBar
INCR Burst Read
MemWr 32 (3DW) of PcieBar
INCR Burst Write
MemRd 64 (4DW) of PcieBar
INCR Burst Read
MemWr 64 (4DW) of PcieBar
INCR Burst Write

关于此IP的处理规定,当处理长度超过一个双字(Dword)的Pcie请求时,主AXI接口上的数据突发传输(burst)长度将始终等于AXI数据总线宽度,即使来自PCIe链路的请求长度短于AXI总线宽度。

从桥AXI写选通(wstrb)信号可用于实现数据对齐地址边界。在有效数据周期开始时,写选通信号可为0,并根据该信号计算地址偏移。从桥接口发起的所有事务将由IP核进行必要调整和流量控制。该接口遵循AXI4协议规范,支持最大4KB的突发传输。IP核将根据PCIe最大读请求尺寸(MRRS)、最大有效载荷尺寸(MPS)及读完成边界(RCB)自动拆分事务。因此,AXI域的单次请求可能在PCIe域生成多个请求,IP核会动态调整PCIe请求数量以避免完成缓冲区溢出。

上述详细说明在pg194-axi-bridge-pcie-gen3-en-us-3.0.pdf文档的P65页。

PCIe和AXI总线之间的地址转换和配置

BAR配置与地址转换

BAR寻址机制

  • ​Aperture_Base_Address_n​(3.0版本上未开放给用户)
    表示GUI中第n个BAR的基地址,在地址转换时视为偏移量0x0。
  • ​Aperture_High_Address_n​(3.0版本上未开放给用户)
    表示GUI中第n个BAR的最高有效字节地址(地址转换规则详见下文)。
  • ​AXI_to_PCIe_Translation_n​
    定义第n个BAR的AXI→PCIe地址映射关系。

AXI BAR大小由Aperture_Base_Address_nAperture_High_Address_n差值决定,需满足,必须为2的幂次方,最小为4K。

发往桥核的PCIE数据包必须落在对应的BAR的基地址与最高地址范围内。如果超出范围,将阻止进入IP。

Address Translation地址转换

支持两种配置方式。

通过IP 界面配置。

寄存器方式配置。

附件cpm4-bridge-v2-1-register.csv下载地址

Bridge Register Space • Versal Adaptive SoC CPM DMA and Bridge Mode for PCI Express Product Guide (PG347) • 阅读器 • AMD 技术信息门户网站

这里看一下官方给的例子

32位PCIE地址映射配置示例

本示例显示了设置三个独立的AXI BAR和将AXI地址转换为PCIe的远程32位地址空间的通用设置。

AXI BAR0:

Aperture_Base_Address_0:0x00000000_12340000。

Aperture_High_Address_0:0x00000000_1234FFFF。(64K)

AXI_to_PCIe_Translation_0:0x00000000_56710000。

实例向AXI AWADDR写地址通道写入地址0x00000000_12340ABC。这个地址在BASE地址范围内,中间地址为0x0ABC在加上AXI_to_PCIe_Translation_0:0x00000000_56710000。最后PCIE的地址为0x56710ABC。

AXI BAR1:

Aperture_Base_Address_0:0x00000000_ABCDE000。

Aperture_High_Address_0:0x00000000_ABCDFFFF。(8K)

AXI_to_PCIe_Translation_0:0x00000000_FEDCD000。

实例向AXI AWADDR写地址通道写入地址0x00000000_ABCDF123。这个地址在BASE地址范围内,中间地址为0x0ABC在加上AXI_to_PCIe_Translation_0:0x00000000_FEDCD000。最后PCIE的地址为0xFEDC1123。

PCIe将地址转换到远程AXI地址空间

设置两个的64位PCIE的BAR。

PCIe BAR0基地址:0x20000000_ABCD8000。(64位启用)

C_PCIEBAR2AXIBAR_0,PCIE to AXI Translation:0x00000000_12340000,高16位(Bits 63-48)必须为0(AXI地址48位约束),Bits 14-0必须为0,非零值视为无效。

转换流程,输入pcie地址,0x20000000_ABCDFFF4(访问BAR0),匹配BAR的范围,0x20000000_ABCD8000,32KB到0x20000000_ABCDFFFF。

偏移量 = PCIe地址 - BAR基地址  
        = 0xABCDFFF4 - 0xABCD8000 = 0x7FF4  
AXI地址 = C_PCIEBAR2AXIBAR_0 + 偏移量  
        = 0x12340000 + 0x7FF4 = 0x0000_12347FF4  

最后输出的AXI地址应该是0x0000_12347FF4 。

官方的图片可能存在笔误。详情见pg194-axi-bridge-pcie-gen3-en-us-3.0.pdf文档的P72页。

好了关于这个IP的重点功能这里已经介绍完了,IP实现了PCIE和AXI之间的地址数据转换。用户可以像操作AXI总线去操作PCIE。特别需要注意的地方是PCIE和AXI的地址转换规则。

AXI Central Memory Access(CDMA)

这里使用CDMA来进行数据搬移,将FPGA内部缓存的数据(DDR或者BRAM)通过PCIE发送上位机的内存上。或者将上位机内存中的数据通过PCIE下发到FPGA内部缓存中。实现DMA数据搬移的IP有几种。

AXI Central Memory AccessCDMA:提供高带宽的直接存存储访问,连接内部的源地址和目的地址。

AXI Datamover:AXI Datamover是一个重要的基础IP,Xilinx 所有的DMA IP基本都包含这个模块,该模块可以将AXIS与AXI格式的数据进行转换。

AXI DMA Controller:AXI DMA Controller为AXIS和AXI4接口的转换(数据存储)提供了一个可由软件控制(通过AXI Lite接口实现)的简单方式。

AXI Multichannel DMA:没用过这个,多通道AXI DMA版本。

这里我们使用之前熟悉过的AXI Central Memory AccessCDMA这个IP。

架构框图

从框图中可以看到IP支持三种端口。

M_AXI_SG端口:这个端口可以提高效率。CPU需要执行的操作可以提前做成描述符的形式写入到内存中,SG端口去读取内存中的描述符并控制CDMA寄存器。描述符中会配置当前搬移的源地址和目的地址,本次搬移的数据量。以及下一个描述符的地址。一次搬移完成后会更新链表状态。本次设计不使用描述符。感兴趣的可以去尝试使用描述符提升DMA效率,缓解CPU的压力。

M_AXI端口:通过该端口完成数据搬移。核心就是通过DATA moverIP实现。

S_AXI_LITE:通过这个端口配置CDMA的寄存器。

Register Space

Address Space  Offset
Name
Description
00h
CDMACR
CDMA控制寄存器
04h
CDMASR
CDMA状态寄存器
08h
CURDESC_PNTR
当前描述符指针(低32位)
0ch
CURDESC_PNTR_MSB
当前描述符指针(高32位)
10h
TAILDESC_PNTR
尾部描述符指针(低32位)
14h
TAILDESC_PNTR_MSB
尾部描述符指针(高32位)
18h
SA
源地址(低32位)
1ch
SA_MSB
源地址(高32位)
20h
DA
目标地址(低32位)
24h
DA_MSB
目标地址(高32位)
28h
BTT
传输字节数寄存器
SA (CDMA Source Address – Offset 18h)

此寄存器为AXI CDMA的简单DMA传输提供源地址。

DA (CDMA Destination Address – Offset 20h)

此寄存器为通过AXI CDMA进行简单DMA传输提供目标地址。

BTT (CDMA Bytes to Transfer – Offset 28h)

这个寄存器用于设置AXI CDMA简单DMA(Simple DMA)传输的字节数,写入该寄存器值将​​自动启动传输​​。

最多支持67108863Bytes传输。

IP配置

AXI Bridge for Pcie Gen3 Subsystem

第一页,配置PCIE的模式,引脚时钟,AXI时钟。

第二页,配置PCIE的设备号,Vendor ID和Device ID以及Class Code。

第三页,配置PCIE的BAR,设置BAR的大小。以及PCIE to AXI Translation ,PCIE地址转换到AXI总线的地址。这里只使用了BAR0。

第四页,配置PCIE的中断相关的类容。这个默认即可。

第五页,配置AXI BARs。设置AXI to PCIE translations,这里也只设置一个AXI BAR,这里配置可以通过lite总线修改(地址范围:0x208 - 0x234),即将AXI突发的地址转换到PCIE的地址。

第六页,配置请求数量。IP默认参数无法修改。

第七页,配置调试接口,暂时不需要。

AXI Central Memory Access(CDMA)

CDMA配置界面。不使用SG端口。

方案测试

方案测试目前没有暂时没找到合适的硬件验证。详细的测试过程,以及驱动编写再后续继续更新。

使用WinDriver配置CDMA寄存器。这里只使用简单的配置过程。

18:配置源地址。

20:目标地址。

28:突发传输字节数。

还需要配置AXI_PCIE的寄存器。

0x208,20C:AXI和PCIE之间的地址转换。AXI Base Address Translation,这里对应你上位机分配的内存空间,如果是EP与EP之间传输即对应PCIE设备BAR空间(其实也是一段内存)。

启动流程

DMA写入。即从上位机传输数据到PCIE设备。驱动分配一段内存,用于存放数据,比如说创建连续数。一次配置本次分配内存地址到208,20C。配置本次传输的源地址和目标地址。这里是写入,即源地址为AXI_PCIE。目的地址为BRAM空间。配置完成后写入本次突发传输的长度。即28寄存器。开始本次传输。

DMA读出。即从FPGA传输数据到上位机。还是一样的,驱动需要先分配一段内存,用于存放数据。FPGA中数据存入BRAM中,达到设置个数后中断告知上位机。上位机获取到后,启动DMA读取数据,配置源地址和目标地址。这次源地址为BRAM,目标地址为AXI_PCIE。配置本次分配的内存地址208和20C。配置完成后写入本次突发传输的数据长度。开始本次传输。

PTP传输。在一些设备中,需要借用PCIE完成数据大规模传输。在两个EP设备之间高速传输数据,数据流不通过上位机的参与,直接传输到另外一个设备。

启动流程。上位机获取A设备的BAR空间对应的内存地址,上位机获取B设备的BAR空间对应的内存地址。数据流A-B。A数据缓存在BRAM中,达到阈值,启动中断告知上位机。配置本次传输的源地址和目的地址,BRAM到AXI_PCIE。配置B设备分配的内存空间地址到208和20C。配置完成后写入本次突发传输的数据长度。开始本次传输。

一些测试过程的ila信息。

后续总结

本次方案全程使用xilinx提供的IP完成本次DMA操作。需要重点理解其中”PCIe和AXI总线之间的地址转换和配置“这部分内容。另外需要看懂本次设计的DMA传输过程。即本次设计的逻辑框图。理解DMA传输的方式。

本次未涉及驱动部分的代码,驱动部分代码由windriver软件自动生成。详细使用说明可以看我之前的文章。

Windriver驱动开发工具使用快速入门-CSDN博客

寄存器配置思路即”启动流程“中描述的过程。

不足的地方,未尝试使用CDMA这个IP的SG模式,导致本次设计方案的PCIE总线效率上不去。详细测试对于GEN3X8效率只能达到百分之十左右,由于博主的驱动编写能力不足。这里就不展示驱动代码了。

提高PCIE总线效率的思路,使用CDMA的SG模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值