ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RK3588+FPGA PCIe DMA性能优化实战:从1.6GB/s到3.5GB/s

RK3588+FPGA PCIe DMA性能优化实战:从1.6GB/s到3.5GB/s 前阵子做机器视觉项目瑞芯微RK3588做主控FPGA做多路图像采集和预处理两者之间走PCIe核心数据搬运全靠DMA。第一版调通时实测写带宽只有1.6 GB/s读带宽更是连900 MB/s都不到可这条PCIe 3.0 x4链路的上限是将近4 GB/s。翻遍了Xilinx论坛和Rockchip的文档反复调设备树、驱动参数和FPGA逻辑最后把写带宽压到3.5 GB/s读带宽也突破了3 GB/s。这个优化过程踩了不少坑也把PCIe DMA整条链路的细节彻底摸了一遍。这篇文章适合正在做RK3588 FPGA高速数据传输的工程师无论是做图像采集、软件无线电还是存储加速只要你想把PCIe DMA的性能从“能跑”压榨到“跑满”这篇实战记录应该能帮你少走很多弯路。下面我就从方案选型开始把整个调优过程拆开讲重点放在为什么这样优化、以及优化后实测的变化上。1. 选型阶段为什么是RK3588、FPGA和PCIe DMA的组合1.1 接口对比选型PCIe凭什么胜出RK3588作为一颗旗舰级SoC外设接口非常丰富能跟FPGA高速互通的候选就有USB 3.0、千兆/万兆以太网、SATA、PCIe。那么为什么最终选择PCIe直接看一组对比数据就清楚了。USB 3.0 Gen2理论带宽10 Gbps换算下来约1.2 GB/s实际有效带宽打八折也就1 GB/s上下。千兆以太网更不用提125 MB/s封顶连高分辨率图像流的零头都喂不饱。万兆以太网虽然能到1.2 GB/s左右但延迟高、MAC和PHY成本不低而且RK3588原生不带万兆控制器得外接网卡芯片。SATA 3.0理论6 Gbps实际约550 MB/s同样不太够看。PCIe 3.0 x4就完全不同了单向理论带宽接近4 GB/s延迟在微秒级别还能直接映射到处理器地址空间FPGA里的寄存器、FIFO、BRAM都能像访问内存一样直接读写。对多路图像采集、高速ADC数据流、AI推理加速这类场景PCIe几乎是唯一能同时满足带宽、延迟和CPU占用率要求的高速接口。说白了选PCIe不是因为它酷而是别的接口在这个带宽需求下根本接不住。1.2 DMA vs PIO为什么“硬件搬运”是唯一可行解选定了PCIe下一个关键决策是数据通路用PIOProgrammed I/O还是DMA。PIO模式下CPU直接通过BAR空间读写FPGA的寄存器或FIFO一次32位访问要经历一个完整的PCIe事务如果是读操作还要等FPGA端响应回来。我做了一个最简单的测试用PIO方式从FPGA的AXI BRAM里读32 KB数据耗时约12毫秒折算下来不到3 MB/s。为什么这么慢因为PCIe读事务延迟高CPU每次读都要发起请求、等待TLP返回、解析数据加上RC内部的地址翻译和同步开销吞吐上不去。这还算快的如果FPGA端逻辑响应不及时一个读请求卡几百个时钟周期速度会更难看。DMA的核心理念是把“数据搬运”这件事外包给硬件引擎。以FPGA端集成XDMA IP核为例CPU只需要把源地址、目的地址、传输长度写进DMA描述符硬件就会自动通过PCIe Bus Master方式发起读写事务批量搬运数据。整个传输过程中CPU基本不参与只有在描述符执行完毕、硬件产生中断时才需要介入一次每次中断的CPU开销大约几微秒。这就好像CPU是公司老板DMA是物流车队老板只负责下订单写描述符和签收通知处理中断真正搬货的活儿全由车队干了。1.3 RK3588的PCIe资源盘点该用哪一路RK3588的PCIe资源比较丰富但并不是每一路都一样强。根据芯片手册RK3588内部有多个PCIe控制器其中性能最强的是PCIe 3.0控制器支持x4链路可以配置成x4/x2/x1同时支持RCRoot Complex和EPEndpoint模式。另外还有若干PCIe 2.0控制器带宽相对较低通常用来接WiFi网卡、SSD或者扩展卡。做高速数据通信首选就是PCIe 3.0 x4这路也就是设备树里常见的pcie30_4l节点。它在物理上可以跟部分SATA接口复用需要根据实际板卡设计在设备树里做好mux配置。这块有个容易踩的坑如果板卡上PCIe和SATA引脚复用没配好PCIe链路经常会出现枚举不到设备或者链路直接断电的情况。另外要注意RK3588的PCIe控制器虽然是定制的DW PCIe变体但Linux驱动支持已经比较成熟。只要设备树配置正确lspci能看到设备后续DMA的调优就都有基础。如果设备树配错连设备都枚举不出来后面所有优化都无从谈起所以这个环节值得花时间仔细确认。2. 硬件设计与链路初始化第一步决定成败2.1 FPGA端IP核选型XDMA还是纯PCIe硬核FPGA端怎么实现PCIe接口决定了整个DMA方案的复杂度。目前主流做法有两种一是用纯PCIe硬核IP如Xilinx 7 Series Integrated Block for PCIe只做传输层接口DMA逻辑完全自己写二是直接用Xilinx的XDMA IP核DMA/Bridge for PCI Express它把DMA引擎、描述符管理、中断控制器都集成好了用户逻辑只需要对接AXI接口。我的建议是除非你有特别定制化的DMA需求否则优先用XDMA。原因很简单——XDMA自带Linux驱动用户态有/dev/xdma0_h2c_0、/dev/xdma0_c2h_0这类设备节点配合官方测试工具就能快速验证链路而纯PCIe硬核方案意味着DMA引擎、SG列表管理、中断控制全部手写光是把一个可靠且高性能的DMA通路调通就要多花至少一两个星期。XDMA配置时几个关键参数链路宽度和速度要和RK3588侧对齐例如Gen3 x4DMA通道数根据业务需求选AXI接口类型有两种可选——AXI4 Memory Map或AXI4-Stream。图像类业务通常选AXI4-Stream数据连续、没有地址开销寄存器访问类业务通过AXI4-Lite接口或AXI4接口即可。2.2 时钟、复位与电源最容易忽略的“三件套”PCIe链路能正常训练硬件上靠的是三样东西参考时钟、复位时序、供电。这三个环节任何一个出问题表现都是千奇百怪的链路故障而且很难排查。参考时钟方面PCIe要求100 MHz差分时钟抖动指标非常严格。RK3588的REFCLK输出脚可以直接连到FPGA的PCIe参考时钟输入但走线阻抗要控制好通常要求100欧姆差分阻抗。我之前有一块板子FPGA的REFCLK走线经过了一个连接器导致信号质量劣化Gen3链路经常训练失败最后只能被迫锁定Gen2性能直接腰斩。这个问题在示波器上看眼图才能发现普通的逻辑分析仪根本查不出来。复位时序是另一个高频翻车点。PCIe规范要求PERST#信号在供电稳定后至少保持100毫秒再拉高并且要等参考时钟稳定。有些FPGA开发板默认复位电路不能满足这个时序表现为10次上电有6次枚举失败。解决办法是检查硬件原理图确保复位信号由RC端控制或者用FPGA内部逻辑做延迟释放。供电方面FPGA的PCIe高速收发器对电源纹波敏感尤其是MGTAVCC和MGTAVTT这两路。我遇到过DMA传输偶发数据出错查了很久发现是FPGA的PCIe电源纹波超标更换了LDO供电方案后问题消失。如果条件允许给PCIe收发器供电的电源轨尽量留足裕量纹波控制在20 mV以内比较稳妥。2.3 设备树配置与链路枚举调通硬件没问题之后软件这边第一步是让RK3588能枚举到FPGA设备。设备树里需要把PCIe节点打开配置链路速度和lane数。下面是我在项目里用过的关键配置pcie30_4l { status okay; max-link-speed 3; // Gen3 num-lanes 4; // x4 reset-gpios gpio4 RK_PB6 GPIO_ACTIVE_HIGH; vpcie3v3-supply vcc3v3_pcie; rockchip,bifurcation; // 如需拆分lane };注意reset-gpios这个属性必须指到控制FPGA PERST#引脚的GPIO而且极性要跟硬件原理图一致。配错了最常见的现象是系统启动后lspci里什么都看不到。枚举调试三板斧# 查看PCIe设备列表 lspci # 查看链路状态和协商速度 lspci -vvv -s 01:00.0 | grep -E LnkSta|LnkCap|DevCap|DevSta # 查看内核PCIe相关日志 dmesg | grep -i pci正常情况下LnkSta应该显示Speed 8GT/s, Width x4这就是Gen3 x4协商成功。如果显示的是Speed 2.5GT/s或者Width x1链路明显降级了优先检查硬件连接和参考时钟再考虑用max-link-speed 2降到Gen2先跑通功能。还有一种情况是枚举出来了但Region 0: Memory at ignored说明BAR空间分配有问题需要检查设备树里的ranges和bus-range属性。3. 驱动与DMA通路搭建把数据搬起来3.1 XDMA驱动移植从FPGA到RK3588的桥Xilinx官方提供的XDMA Linux驱动支持两种接入方式一种是作为平台设备直接挂在Device Tree下适合FPGA作为固定Endpoint的场景另一种是通过标准的PCIe probe流程注册。在RK3588上使用强烈推荐走PCIe枚举后probe的方式也就是把FPGA当成一颗普通的PCIe功能设备来处理。XDMA驱动加载成功后系统会创建/dev/xdma0_h2c_0、/dev/xdma0_c2h_0、/dev/xdma0_user等设备节点。其中h2c表示Host to Card主机到FPGAc2h表示Card to HostFPGA到主机user节点用来访问FPGA内部的寄存器空间。我建议先用官方xdma_test工具裸测一遍这是最干净的验证链路# 向FPGA写256MB数据 ./xdma_test -w -l 256 -f /dev/xdma0_h2c_0 # 从FPGA读256MB数据 ./xdma_test -r -l 256 -f /dev/xdma0_c2h_0第一次跑通时看到读写数据正确、CRC校验通过说明PCIe枚举、BAR空间映射、DMA引擎、中断上报这一整条链路都通了。这时候的带宽数据可能不太好看先别急着优化正常现象。3.2 SG描述符DMA能干活的底层逻辑熟悉了XDMA驱动之后有必要理解一下它背后的SGScatter-Gather描述符机制。DMA传输要求源地址和目的地址都物理连续但实际系统内存可能是碎片化的。SG机制把一次大块DMA拆成多个小段每段都有一个描述符记录地址、长度和下一个描述符指针硬件按链表顺序逐个执行执行完最后一个描述符后产生中断。XDMA驱动内部会分配一段一致性DMA内存来存放描述符表然后把用户传入的buffer地址做映射。这里有个非常重要的细节用户态程序传下来的buffer可能是虚拟地址而且不一定物理连续所以驱动必须用dma_map_sg或者get_user_pages做物理页锁定和地址映射。如果buffer跨页过多SG条目数量暴涨描述符表的维护开销也会显著增加。实际项目里我习惯直接用dma_alloc_coherent分配驱动内部buffer避免用户态内存映射的额外开销然后通过mmap把这个buffer映射给用户态程序使用。这样DMA搬运的源地址和目的地址天然物理连续描述符数量少硬件处理快吞吐率明显更高。3.3 中断路径选择MSI-X与中断合并DMA传输完成必须通知CPU这依赖中断机制。PCIe支持传统INTx中断和MSI/MSI-X中断其中MSI-X是针对多队列最好的方案。XDMA IP默认支持MSI-X中断可以为每个DMA通道分配独立的中断向量这样CPU可以精确知道哪个通道完成了传输不需要靠读状态寄存器去轮询判断。RK3588对MSI-X的支持要看内核版本和驱动早期内核可能存在MSI-X支持不完善的问题。如果你在dmesg里看到类似Failed to enable MSI-X的报错先用INTx方式跑通流程再回头查MSI-X配置。中断数量对CPU占用率的影响非常大。假设每秒钟产生10万次DMA中断每次中断处理哪怕只要5微秒CPU就有50%的时间耗费在中断处理上。解决办法是中断合并Interrupt CoalescingXDMA驱动可以通过模块参数调节合并阈值和超时时间。大概意思是要么攒够N个描述符完成再上报一次中断要么等到T微秒再上报取先到的条件。这个参数的设置要跟业务节奏匹配。如果FPGA是周期性突发传输中断合并很有效如果是低延迟、高实时性的单笔小包传输中断合并反而增加延迟需要权衡。在图像采集场景下一般一帧数据触发一次中断比较合理合并阈值可以设成一帧包含的描述符数量。4. 性能测试与瓶颈分析用数据说话4.1 基线测速第一版能跑多少优化之前必须先建立基线。我用XDMA官方工具分别做了Host to CardH2C和Card to HostC2H两个方向的块传输测试buffer大小从1 MB到512 MB不等连续跑3次取最好成绩。基线数据大概是这样的传输方向Buffer大小实测带宽带宽利用率H2C1 MB0.8 GB/s20%H2C64 MB1.4 GB/s36%H2C512 MB1.6 GB/s41%C2H1 MB0.4 GB/s10%C2H64 MB0.8 GB/s20%C2H512 MB0.9 GB/s23%看到这个数据第一反应是链路可能降级了但lspci -vvv明明显示LnkSta: Speed 8GT/s, Width x4。链路是Gen3 x4没问题问题出在传输效率和驱动参数上。注意到一个规律buffer越大带宽越高。这说明每次DMA传输的开始和结束都有不小的固定开销小buffer时开销占比太大掩盖了真实带宽能力。这也从侧面验证了SG描述符机制的开销分析——描述符越少效率越高。4.2 瓶颈定位带宽到底去哪儿了基线数据出来了下一步是定位瓶颈。我梳理了整个数据通路的各个环节逐个排查第一PCIe链路本身。lspci确认链路Gen3 x4理论带宽3.94 GB/s链路没有瓶颈。第二PCIE配置空间参数。查看PCIe设备控制寄存器发现MPS默认是128BMRRS默认也是128B。这两个参数直接限制了每个TLP包能传输的数据量128B的包在高速链路下会产生大量包头开销效率很低。第三XDMA驱动默认参数。驱动初始化时可能没有开启较大的突发传输模式DMA每次发起读请求都使用默认的MRRS导致C2H方向读带宽上不去。第四中断频率。没有开中断合并时每一次DMA传输都产生中断512 MB的buffer被分成大量描述符中断风暴直接拖累吞吐。第五FPGA端逻辑。XDMA IP核生成时AXI数据宽度、突发长度等参数如果偏小也会限制实际吞吐。这个我一开始没注意后来发现FPGA端AXI4接口数据宽度默认只有64位突发长度16明显不够用改为128位数据宽度、突发长度256后带宽提升显著。4.3 性能指标表各配置组合下的实测数据为了量化每一项优化带来的收益我专门做了一组对照实验每次都只改动一个变量记录两个方向的带宽变化配置组合H2C带宽C2H带宽备注默认配置1.6 GB/s0.9 GB/sMPS/MRRS128BMPS256B, MRRS256B2.1 GB/s1.3 GB/s增益明显MPS512B, MRRS512B2.6 GB/s1.8 GB/sC2H提升最大 关闭XDMA中断合并为最优值2.9 GB/s2.2 GB/s减少中断扰动 FPGA AXI总线位宽翻倍3.3 GB/s2.8 GB/sFPGA侧数据路径优化 CPU亲和性绑定巨页3.5 GB/s3.1 GB/s最终成绩这个表格很直观地展示了优化的层次感先调对PCIe参数再优化驱动和中断最后才是FPGA逻辑和系统级配置。每一步都有收益但收益幅度不同建议按照这个顺序来不要跳过基础步骤直接搞FPGA逻辑优化否则低层瓶颈会掩盖高层优化的效果。5. 优化实操把带宽压榨到极限5.1 关键参数调优MPS、MRRS与缓存一致性MPSMax Payload Size决定了一个TLP数据包里最多能承载多少字节的写数据MRRSMax Read Request Size决定了一次读请求最多能向对端请求多少字节。二者直接影响PCIe链路上的传输效率是整个优化过程中投入产出比最高的两个参数。用生活化的类比理解MPS就像集装箱的箱体大小MRRS像一次能下单订购多少集装箱的货。箱体太小同样的货物需要更多次运输每箱还有固定的“运费”TLP包头开销。将MPS从128B调到512B每个写TLP能承载的数据量是原来的4倍但包头开销基本不变效率自然提升。在RK3588的Linux系统中可以用setpci直接修改设备的配置空间寄存器# 查看当前值 setpci -s 01:00.0 0x04.w # 设置 MPS512B (位[7:5]010), MRRS512B (位[14:12]010) # 即写入 0x2040 setpci -s 01:00.0 0x04.w0x2040但要注意MPS值必须同时被RC和EP支持如果FPGA端生成XDMA IP时配置的最大负载能力只有256B你强制设置512B可能导致链路训练失败或传输错误。安全做法是查看FPGA端提供的配置或者从lspci -vvv的DevCap: MaxPayload 512 bytes确认能力上限。还有一点关于缓存一致性DMA搬运涉及CPU缓存和内存之间的同步。使用dma_alloc_coherent分配缓冲区时驱动会保证DMA和CPU看到一致的数据不需要手动处理缓存刷写。如果自己通过kmalloc加dma_map_single实现则必须在合适的时机调用dma_sync_single_for_cpu或dma_sync_single_for_device这个写错会导致数据错乱而且问题极其隐蔽可能在特定buffer大小下才出现。5.2 H2C与C2H带宽不对称问题优化过程中你会发现一个普遍现象H2C写方向带宽总是高于C2H读方向带宽。这不奇怪PCIe的读操作天然有更高的延迟——RC发起一个读请求后要等FPGA端处理完请求、组织数据、返回TLP包整个过程都是串行的而写操作是单向的RC把数据发出去就完事不需要等待响应返回。所以在C2H方向上优化重点就是尽可能减少读请求的往返次数。把MRRS调大一次读请求就能拿回更多数据减少发起读请求的个数。FPGA端也要配合XDMA IP核或者自定义逻辑里读数据路径的FIFO深度要足够让FPGA能够持续返回数据而不是每收到一个读请求才慢吞吞地启动一次读。这里有个实战经验FPGA端响应读请求的时延非常影响C2H带宽。如果FPGA内部从AXI BRAM读取数据需要几十个时钟周期C2H带宽会掉得非常厉害。解决思路是FPGA端用流水线方式提前预取数据或者在XDMA到用户逻辑之间加一个深度足够的数据缓存让XDMA发起的突发读请求能被连续返回的数据流“喂饱”。5.3 CPU亲和性与中断优化DMA传输虽然不占用CPU但DMA完成中断的处理仍然需要CPU参与而且数据最终是要被CPU或GPU消费的。在这种情况下把中断绑定到特定的CPU核上能让缓存局部性变好减少缓存失效和数据跨NUMA节点访问的开销。RK3588是大小核架构4个Cortex-A76大核加4个Cortex-A55小核。DMA相关的核间中断和用户态处理程序强烈建议绑定到大核上。可以这样操作# 查看当前xdma中断号 cat /proc/interrupts | grep xdma # 将中断绑定到大核例如CPU2和CPU3 echo 0x0c /proc/irq/46/smp_affinity另外Linux内核的irqbalance服务有时会把PCIe中断在不同核之间来回迁移对性能有负面影响。做性能测试时建议关掉它systemctl stop irqbalance systemctl disable irqbalance对于用户态的QDMA/XDMA处理程序可以用taskset绑定到与中断相同的CPU核上或者用CPU隔离参数isolcpus2,3把大核隔离出来专供业务逻辑使用。实测这个调整对C2H方向还有额外几个百分点的提升主要原因是CPU不用切换上下文缓存命中率上去了。5.4 FPGA端数据路径优化跑完以上所有优化后我当时的H2C带宽到2.9 GB/sC2H到2.2 GB/s已经比初版强很多但离理论上限还有距离。进一步分析发现瓶颈已经转移到FPGA内部的数据路径上。检查XDMA IP核的配置发现AXI4接口数据宽度是64位最大突发长度16。在Gen3 x4的链路速度下硬件可以接收更宽的总线和更长的突发。把AXI4数据宽度改为128位突发长度提升到256FPGA内部AXI时钟提高到250 MHz以后C2H方向带宽直接从2.2 GB/s跳到了2.8 GB/s。用户逻辑侧也有讲究。如果你的FPGA设计里XDMA的AXI接口直接连到一个窄总线或者低时钟域这个瓶颈就是不可逾越的。比如XDMA的AXI接口是128位250 MHz理论带宽4 GB/s但你的图像处理逻辑只有32位100 MHz的接口那最大只能提供400 MB/s整个链路被卡死在这里。所以设计FPGA数据通路时关键路径一定要保证足够宽、足够快至少不低于PCIe一侧的吞吐能力。另外需要关注FIFO深度。DMA传输是突发式的数据到达速率不均衡如果用户逻辑到XDMA之间的FIFO太浅容易发生上溢写方向或下溢读方向导致总线空闲等待带宽就会下滑。我一般会把这个FIFO设成2 KB以上具体大小根据单次DMA的最大突发长度来算。6. 从踩坑到避坑常见问题与排查实录6.1 链路协商不稳定或降速这是最常见的坑具体表现是每次上电协商结果不一样有时候Gen3 x4有时候降到Gen2或Gen1甚至直接枚举失败。排查思路从硬件到软件逐步收窄。先看供电和参考时钟用示波器看REFCLK波形是否干净PERST#时序是否满足要求。再看PCIe差分对走线如果板子没有做阻抗控制或者走线过长、过孔过多信号完整性问题是绕不开的。最后可以检查设备树的max-link-speed是否设置得太乐观RK3588某些早期内核版本对Gen3的支持不完善可以先锁Gen2跑稳定再研究Gen3。软件方面可以用lspci -vvv查看当前的链路状态确认两端的LnkCap和LnkSta。如果FPGA端只报告LnkCap: Speed 8GT/s, Width x4说明FPGA配置没问题如果只认到x2甚至x1检查FPGA引脚约束里是否把所有lane都约束出来了。我以前踩过一个坑FPGA工程里只约束了x4 lane中的2对差分引脚实际协商就只有x2带宽凭空少一半。6.2 DMA数据错位与CRC错误DMA传完的数据偶尔有错位或者CRC校验错误这个问题非常抓狂因为它不是100%复现可能跑几百MB数据才出错一次。我遇到过的原因有三个方向硬件电源纹波、驱动缓存一致性问题、FPGA时钟域问题。电源纹波导致高速收发器误码这个比较难查如果你发现出错的频率跟FPGA温度或负载有强相关性先查电源。缓存一致性问题则和驱动实现高度相关检查DMA缓冲区是否用dma_alloc_coherent分配以及驱动是否在正确时间点调用了cache sync函数。FPGA时钟域方面如果XDMA的用户AXI接口和内部逻辑的时钟域不同步跨时钟域处理没有做好也会偶发字节错位。排查利器是FPGA的ILAIntegrated Logic Analyzer和PCIe CRC统计。XDMA IP内部有PCIe错误统计寄存器出现CRC错误会累加。通过XDMA的user寄存器读取这些统计值可以判断错误是发生在链路层还是更高层效率很高。6.3 中断风暴与CPU占用过高如果你发现DMA搬运数据时系统CPU占用率飙到100%多半是中断风暴。初版驱动没有开中断合并时每个描述符完成都会触发中断512 MB buffer可能被拆成几千个SG条目几万个中断一起压过来CPU自然就爆了。解决办法在前面提过开启中断合并调整irq_coalesce和irq_timeout参数。但要小心中断合并参数太激进会导致延迟变高实时性要求高的场景要谨慎。另一个有效方法是一笔DMA传输尽量使用大的SG条目减少描述符数量从源头上降低中断次数。如果是用用户态VFIO方式做DMA可以考虑用轮询模式替代中断模式。轮询在持续高吞吐场景下反而比中断模式更省CPU因为省去了中断处理的上下文切换和保存恢复开销。不过轮询在空闲时比较浪费CPU需要根据业务动态切换。6.4 IOMMU的坑地址转换与性能开销RK3588支持IOMMU默认情况下某些内核配置可能会让PCIe设备也走IOMMU地址翻译。IOMMU打开时DMA操作使用的是IOVA地址而不是物理地址。XDMA驱动默认使用dma_alloc_coherent来分配DMA内存这个接口本身会在IOMMU开启时自动完成地址映射按理说没问题。但实际项目中我遇到过一个怪异问题RDMA大块buffer时地址映射到IOMMU后需要分配连续IOVA当系统内存碎片化严重时IOVA分配失败DMA请求直接被拒绝。表现为大块传输偶尔超时而小buffer完全正常。排查方法是在内核cmdline加iommu.passthrough1或者在设备树里把PCIe节点关联的IOMMU禁用再观察问题是否消失。如果业务数据不涉及安全隔离高性能DMA场景下我建议直接关闭PCIe的IOMMU。RK3588的IOMMU主要用于多媒体编解码、GPU等场景的内存保护PCIe设备走passthrough模式可以降低地址翻译的开销实测也能带来几个百分点的性能提升。当然如果是做安全等级要求高的产品IOMMU还是应该打开牺牲一点性能换内存访问隔离是值得的。最后再分享一个小技巧调PCIe DMA不是一遍过的活我的习惯是每改一个参数都记录当时的配置和带宽数据形成一张类似上文那样的对照表格。这样每次回看都知道哪一步产生了收益哪一步没有效果后续回归调试也不需要从头猜起。RK3588 FPGA的这套组合只要把链路训练、DMA描述符、中断路径、AXI数据通路这几个核心环节都调到位跑到Gen3 x4理论带宽的80%以上是完全可以做到的。
返回列表