手头的这块Bittware VV4板卡吃灰太久,终于找个机会把它跑起来,目标是把开源的100G NIC方案Corundum移植上去。Corundum项目在github上由Alex Forencich维护,几乎把现代网卡该有的东西都开源了:PCIe DMA引擎、收发队列、MAC/PCS、甚至管理面固件;VV4则是Bittware基于Xilinx Virtex UltraScale+ VU4P做的高密度PCIe加速板,板载4个QSFP28光口。把两者拼到一起,等于给一块纯FPGA开发板装上完整的100G网卡数据通路。系列第一篇,先把移植前期的方案梳理、硬件资料分析、约束规划和最容易踩的坑讲清楚。
毕竟是“移植”而不是“从零开发”,核心问题从来不是RTL逻辑怎么写,而是如何把一套原本针对特定板卡写的工程,重新映射到另一块板子的物理资源上。Corundum这套代码质量很高,也做了不少可配置化处理,但要让它在一张原理图完全不同、时钟拓扑不同的板卡上跑起来,中间藏的细节比想象中多得多。这篇记录的是一个完整的决策过程,不打算只贴最终结论。
1. 项目全貌与移植目标拆解
1.1 Corundum到底是一个什么层级的开源网卡方案
先说清楚Corundum的定位。它不是单纯一个MAC IP,也不是一个可以随手跑的demo工程,而是一整套从硬件RTL到Linux驱动全部开源实现的网卡方案。项目里包含数据通路用到的PCIe DMA引擎、支持多队列的调度逻辑、以太网MAC、PCS/PMA、RS-FEC,以及一个基于FreeRTOS跑在MicroBlaze软核上的管理CPU固件。
这套东西最值钱的不是某一个模块,而是完整的数据通路。从主机侧看,它是标准PCIe网卡,驱动加载后会出现eth口;从FPGA侧看,DMA引擎把PCIe事务翻译成AXI-Stream报文,经过队列调度、checksum offload、过滤模块,最后推到高速串行收发器上。官方默认工程通常针对Xilinx VCU118开发板,用的是Virtex UltraScale+ VU9P芯片,板载单个QSFP28,支持100G/40G/25G/10G自适应。
移植到VV4,本质上是把这套RTL里和具体板卡绑定的那一层全部换掉,再重新适配物理引脚、时钟和PCIe配置。逻辑部分不需要大动,但工程顶层、约束、IP例化参数、DMA地址映射这些全都要过一遍。
1.2 Bittware VV4凭什么适合承接这个移植
VV4是Bittware家一张很典型的FPGA加速卡,核心是Virtex UltraScale+ VU4P,封装FLGA2892,速度等级-2LE。板卡上最重要的接口资源是4个QSFP28,意味着物理层最多能同时出4路100G,或者更多的25G/10G组合。PCIe方面是Gen3 x16金手指,由板上的PCIe SerDes连接到FPGA,作为主机通信的主干。板载存储、各种管理接口也都齐全。
选择这张卡承接Corundum移植,有几个很现实的理由。第一,100G NIC的核心物理资源是高速串行收发器,VV4的4个QSFP28正好是标准100G端口形态,QSFP28换算成电接口就是4路25G SerDes;Corundum的100G MAC在数据通路层面是4条25G PCS并行,映射到GTY上刚好一一对应。第二,VV4的PCIe Gen3 x16信号接通到FPGA的PCIe硬核区域,和Corundum默认依赖的Xilinx XDMA IP位宽、协议栈天然匹配。第三,这块板子在工业市场已经有不少部署案例,时序约束、板级设计相对成熟,资料虽然不对外开放太多细节,但找Bittware要一套基础工程模板并不难。
当然,VU4P这块芯片本身的逻辑资源并不算宽裕。VU4P大约百万级逻辑单元,BRAM和DSP相对中等,跑一套完整的100G NIC加多队列DMA,LUT消耗会非常接近上限,时序收敛需要认真对待。这在实际移植过程中直接决定了方案的端口规模,后面会专门分析。
1.3 移植工作的三层边界划分
动手之前,先把移植工作按层次拆开,每层的工作量和风险完全不一样。
第一层是物理资源映射。包括GTY高速收发器在VV4板上的位置、QSFP28对应哪几个Bank、PCIe引脚在FPGA封装上的具体管脚、差分时钟输入的引脚分配、LED/复位/串口等杂项管脚。这一层是纯体力活,但错一个PACKAGE_PIN,轻则编译失败,重则烧板。
第二层是时钟拓扑适配。Corundum内部存在多个时钟域,主线收发时钟、MAC时钟、用户逻辑时钟、PCIe参考时钟、管理固件时钟,每一路都从板卡时钟芯片或晶振汇聚出来。VV4的时钟方案和VCU118不同,需要重新确认每一路时钟的来源、频率、连接到的全局时钟引脚或GTY参考时钟引脚。
第三层是PCIe和DMA配置适配。Corundum依赖Xilinx的XDMA IP核完成PCIe事务到AXI-Stream的转换,同时还有PCIe配置空间、BAR空间、MSI中断等细节。VV4的PCIe引脚位置、参考时钟频率、链路宽度这些参数都需要写进IP配置。
按照这个分层思路,移植工程不再是面对一团乱麻,而是按物理引脚、时钟树、PCIe链路三个维度逐条推进。
提示:尤其推荐在第一层物理资源映射时,把板卡原理图、FPGA的封装引脚文件、Corundum原有的约束文件三份文档摆在桌面上同时核对,所有引脚映射做成一页对照表,后面调试起来会省很多时间。
2. 资料筹备与环境搭建的注意事项
2.1 动手前必须备齐的参考资料
移植的第一步不是写代码,而是把该看的资料搜集齐。我实际用到的核心资料,按工具、硬件、软件三个维度列一下。
硬件资料里最重要的是两块:VV4的硬件手册和原理图。原理图通常找Bittware技术支持要,NDA之类的流程走得比较快。把原理图拿到手之后,要做的事情根据Bittware给的FPGA工程模板来核对:板卡上每个QSFP28的四路GTY在FPGA上的PACKAGE_PIN是哪些、MGTREFCLK引脚接的是哪个时钟源、PCIe金手指的参考时钟是否直接进FPGA、板上有没有时钟Buffer或时钟芯片负责fanout。
Corundum方面的资料,官方GitHub仓库里的源码和文档是最权威的。重点看以下几个文件:工程顶层RTL、约束文件、PCIe和XDMA相关的IP生成脚本,以及附带的README中对不同目标板的说明。Alex在Wiki里对每个子模块都有详细说明,尤其是时钟方案和DMA机制,值得读两遍。
软件环境方面,项目用Vivado开发,我用的版本是2020.2,Corundum这个项目对Vivado版本的兼容性比较挑剔,太新的版本偶发IP核接口变化,太老的版本又可能缺器件支持。VV4用的VU4P需要在Vivado里安装对应器件的支持,一般Vivado默认自带。板卡调试还需要串口终端工具和chipscope调试能力。
2.2 板卡物理资源摸底:GTY与QSFP28的映射
VU4P这颗芯片的高速收发器在封装上分成了好几个Bank区域,其中一部分引脚在VV4板子上被连接到了QSFP28光模块的host接口,其余部分被PCIe金手指占用,还有一部分接到了板内的高速连接器或SRIO接口。
这里需要特别留意的是,VV4板上存在SRIO接口。Bittware在板卡设计上把一组高速SerDes引到了SRIO连接器,但在很多使用场景里,这组SerDes并不直接参与网卡数据通路。你的移植目标如果是让4个QSFP28都吃满,那就要确保QSFP28对应的GTY通道全部是“自由”的,没有被板卡的预设功能或其他逻辑占用。
实际查看约束工程的引脚分配后,我整理了这样一张映射表(表中频道按QSFP28端口索引),这是后面所有工作的起点:
| 端口 | 高速收发器Bank | 数量 | 用途 |
|---|---|---|---|
| QSFP28 0 | 某个GTY Quad | 4路 | 100G主线数据 + 反馈时钟 |
| QSFP28 1 | 某个GTY Quad | 4路 | 100G主线数据 |
| QSFP28 2 | 某个GTY Quad | 4路 | 100G主线数据 |
| QSFP28 3 | 某个GTY Quad | 4路 | 100G主线数据 |
| PCIe | PCIe专用Bank | 16路 | Gen3 x16 |
这张表在实际操作里的意义在于:可以清楚看到4个QSPF28恰好占用了4个GTY Quad Bank,每个Quad的4个通道正好是一组100G lane,非常规整。但也意味着如果后续想加第二个100G端口或更多25G端口,GTY资源并不富余。VU4P上可用GTY总数是有限的,PCIe、SRIO、QSFP28之间属于物理互斥。
注意:高速收发器的Bank规划一定要在布局布线之前确定,并且要对照封装引脚文件检查PACKAGE_PIN有没有写错,尤其是那些名字长得像的引脚。我曾经因为MMCM和GTY的引脚坐标看错,整个工程的时序全部乱掉,排查了整整一个下午。
2.3 时钟树的完整梳理与关键差异
Corundum对时钟的要求相对复杂,至少要保证这些时钟存在且频率正确:
- PCIe参考时钟:标准的100MHz差分参考时钟,直接连接PCIe硬核相对的MGTREFCLK引脚。
- GTY收发器参考时钟:用于100G PCS/PMA的串行时钟,频率通常为156.25MHz或161.1328125MHz(取决于线速率和RS-FEC开关)。
- 用户逻辑时钟:AXI-Stream内部数据通路的时钟,通常是250MHz或322.265625MHz。
- 管理接口时钟:用于配置寄存器访问、AXI-Lite接口,通常100MHz即可。
VCU118板卡上的时钟设计比较典型,PCIe参考时钟、GTY参考时钟和全局时钟都有独立的源。VV4则不一样,板卡使用了一片SI5328系列的时钟发生器芯片,可以把外部参考时钟合成多路低频差分时钟和高速参考时钟。SI5328的输出频率可以灵活配置,但问题在于板卡上只有特定几路时钟被真正连到了FPGA的MGTREFCLK或全局时钟引脚,而不是像VCU118那样“要什么有什么”。
所以我花了不少时间在原理图里追踪每一路时钟扇出到FPGA的哪个Bank哪个引脚,并确认它们是否与约束文件里写的一致。这是一个非常枯燥的过程,但直接决定了后面的时序收敛难度和链路是否能够初始化。
实操心得:如果板卡上SI5328的默认配置不满足需求,不要害怕去改它的寄存器配置,甚至可以通过I2C在FPGA逻辑里控制时钟芯片完成频率切换。很多板卡在参考设计里已经预留了这种控制接口,只是默认没打开而已。
3. 移植过程中的关键技术适配点
3.1 顶层RTL的移植思路与时钟域复位处理
Corundum的顶层模块把数据通路、PCIe、DMA、管理逻辑都组织在一起,通常例化了Xilinx的XDMA IP、MGT IP、以及一部分用户自定义逻辑。移植时,顶层结构基本不用改,但需要把板级相关的输入输出信号在时序约束和引脚分配上全部替换成VV4对应关系。
原生Corundum工程里有些信号名和VV4工程模板不一致很正常,但接口语义要保持一致。比如QSFP28的modsel、reset_l、lp_mode这些管理引脚,在VV4上接法可能不同,有些可能直接拉死,有些是反逻辑。这些在顶层例化里要小心处理,尤其是reset或低有效信号,搞反了光模块不工作,误码率还看不出。
时钟和复位部分,Corundum默认的设计是异步复位同步释放,这个策略非常稳健。移植时,我建议复位逻辑完全复用原工程的,只是把复位源从板卡按钮改成由PCIe的user reset或管理固件触发。这样既能保证逻辑初始化时序,又不依赖操作人员去按按钮。
3.2 PCIe硬核与XDMA IP的参数适配
Corundum的数据通路核心是DMA,而DMA引擎最终通过XDMA IP与主机通信。XDMA的配置包含几组关键参数:PCIe链路宽度(x8或x16)、速率(Gen3)、BAR空间个数及大小、DMA引擎能用的通道数、中断方式(MSI/MSI-X)。
VCU118参考工程默认配置是PCIe Gen3 x16,而VV4的PCIe金手指也是Gen3 x16,这是一个利好消息,理论上IP配置可以直接复用。但有两处需要注意:第一,PCIe参考时钟在VV4上可能直接由主板提供,也可能由板载振荡器产生,两者在XDMA IP的参考时钟源选项里不同;第二,如果VV4的小封装或板卡布局导致部分PCIe lane在物理上未连接,IP配置就必须改成x8,否则链路训练会失败。
另一个细节是XDMA IP内部会生成一个AXI-Lite配置接口和一个AXI-Stream接口。Corundum的管理CPU、寄存器读写、过滤规则配置几乎都走AXI-Lite;DMA数据走AXI-Stream。移植时,必须确认AXI-Lite的地址范围能映射到XDMA BAR空间,地址对齐严格,否则主机软件访问寄存器会莫名出错。
3.3 MAC与PCS层参数:从100G到25G的自适应坑
Corundum的MAC/PCS支持多速率,100G模式使用4个25G通道绑定,40G模式使用4个10G通道绑定,25G模式单通道,10G模式单通道。移植到VV4后,4个QSFP28意味着理论上可以支持4个25G端口、1个100G端口搭配若干25G端口等组合。
但VU4P资源吃紧,每增加一个端口都要额外占用一组完整的MAC+PCS+GTY逻辑。100G全速率模式下,RS-FEC(Reed-Solomon Forward Error Correction)开销很大,既占逻辑资源也占GTY线速率。我建议首版移植先把目标定在单100G端口,也就是第一个QSFP28吃满4×25G,其余先不用,保留足够的资源余量用来调时序和调试。
PCS层有一个容易忽视的参数是RS-FEC使能与否。100G必选RS-FEC工作在KP4码型,这会增加约7%的线速率开销,同时要求GTY参考时钟频率对应调整。如果用DAC线缆短距离互联,RS-FEC可以关,但用光模块长距离必须开。这个参数会影响GTY QPLL的分频系数配置,必须在约束和IP里一起改,否则链路根本起不来。
4. 实际调试过程记录与问题排查实录
4.1 从综合到上板的首轮全流程
把顶层替换成VV4工程模板后,先做了一次完整的综合和布局布线,目标是确认资源占用和时序状况,这一步能暴露出大量引脚分配错误。第一次实现跑完后,看资源报告:LUT消耗已经接近70%,FF超过40%,BRAM接近一半,这个量级对VU4P来说已经不算轻了。
如果此时时序余量是负数,比如WNS在-0.5ns以下,先不要急着改约束,优先检查时钟树是否正确:所有GTY的QPLL是否锁定、时钟频率是否匹配、全局时钟缓冲是否被正确驱动。时序违例在很多情况下不是布线器不够努力,而是时钟约束写错了。
上板调试的第一步不是跑流量,而是先用ILA挂在PCIe AXI-Lite总线上抓配置读写。如果主机侧加载驱动后能正确读写BAR寄存器,说明PCIe通路已经通了;如果连BAR都访问不到,大概率是XDMA配置或PCIe物理链路问题,排查方向会很不一样。
4.2 常见问题速查表
整理一份汇总,遇到问题时优先对照:
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| GTY QPLL无法锁定 | 参考时钟频率不对、RS-FEC参数不匹配 | 检查SI5328输出频率、GTY参考时钟引脚、重新生成IP |
| PCIe枚举不到设备 | XDMA参数错误、参考时钟未接、链路宽度不匹配 | 确认PCIe参考时钟、查看板卡link training状态、用lspci逐级排查 |
| 驱动加载后无法注册网卡 | BAR空间映射错误、中断配置异常 | 检查XDMA的BAR配置、MSI-X是否使能、dmesg日志 |
| 100G链路无法建立 | 光模块未识别、QSFP28控制引脚接错、RS-FEC协商失败 | 检查光模块电接口状态、看PHY状态寄存器、用PRBS测试GTY通道 |
| 收发数据后误码率飙升 | 时钟抖动大、DAC线缆质量差、FEC关闭或参数错误 | 改用短距离DAC线缆、打开RS-FEC、单独用GTY IBERT验证通道质量 |
| 4端口RTL综合后严重时序违例 | 资源过载、时钟共享导致布线拥塞 | 先缩减为单端口,重新布局,再逐步增加逻辑 |
4.3 几个容易被忽略的坑
第一个坑是光模块的reset引脚。VV4上QSFP28模块的reset可能默认是低有效,也可能需要软件控制,如果reset一直拉低,模块根本不会主动进入工作状态。看起来像是链路不亮,实际只是模块没启动。
第二个坑是DAC线缆与光模块的差异。如果是近距离背靠背测试,用DAC直连线比光模块省事得多,但DAC线也有长短和质量的差异,3米以上的DAC在100G下经常随机误码。调试初期最好用0.5米以内的优质线。
第三个坑是GTY收发器的TX termination电阻。不同板卡的PCB走线阻抗、连接器差分对引脚和TX termination设置可能不一致,综合后如果信号质量差,检查GTY TX的预加重和接收均衡参数,这些通常不在默认约束范围内,需要按板卡特性微调。
注意事项:所有PCIe和高速收发器的调试都要在一个干净的主机环境里做,尽量不要插一些杂牌PCIe转接卡、延长线之类的设备。PCIe链路对信号完整性的要求比想象中高,插拔接触不良会导致枚举不稳定或链路速率降级。
5. 后续扩展思路与整体体会
首版跑通之后,可以继续深入的方向其实很清晰。如果你手上有VV4这块卡,并且想把它真正当网卡用,下一步至少能尝试三件事:第一,扩展成多端口模式,把4个QSFP28全部启用,但前提是资源够、时序能收;第二,把Linux驱动里的多队列特性打开,调队列数和中断亲和性,看看实际吞吐和CPU占用情况;第三,接入管理固件,用FPGA里的软核跑FreeRTOS做日志采集、传感器监控、远程管理。
就我个人实际操作过程中的体会来说,Corundum移植到VV4最大的收获不是“最终跑出了100G链路”,而是逼着把整块板卡从头到尾啃了一遍。每一路GTY怎么走线、每一路参考时钟从哪里来、PCIe配置空间里每个字段发生了什么,这些平时做应用层开发根本不会关心的问题,在这里全部变成了务实的基础知识。
如果大家正在做类似的FPGA网卡移植,建议把第一篇的目标定得更克制一点。第一次上板只做一件事:把PCIe链路跑通,然后用IBERT或PRBS验证光模块通路。先证明板卡物理层完全OK,再谈DMA和驱动层。等这套基础都扎实了,几百兆的线速率就不再是障碍,后面的问题更多是软件栈的适配。