☰
Corundum开源100G网卡移植到VV4 FPGA板卡实战记录
2026/9/27 3:55:03 网站建设 项目流程

如果你一直在找一套真正意义上的开源100G网卡方案,那Corundum这个名字你应该不陌生。它不是那种只放一堆RTL代码的PPT开源项目,而是从FPGA固件到Linux内核驱动全部开放、能实打实跑满线速的东西。最近我在做一件折腾事:把Corundum从它熟悉的Xilinx官方开发板环境,移植到Bittware VV4这块商用FPGA板卡上。这个过程远比想象中琐碎——换板卡意味着PCIe路径、GT收发器引脚、时钟树、QSFP28管理、约束文件全都得重来一遍。这篇文章是移植记录的第一篇,先把整体思路、板卡摸底和最容易翻车的地方讲清楚,后面几篇再逐个拆解具体模块的改法。

先说清楚这篇适合谁看。如果你打算基于Corundum做自定义100G网卡、想把手里的非官方FPGA板卡跑成网卡用,或者虽然不搞FPGA但想知道开源网卡到底能不能落地,这篇都值得读完。如果你只是想找现成的商业网卡,那可以关掉了,这里讨论的是“自己动手改RTL”的路线。

1. 为什么偏偏是Corundum和VV4这个组合

1.1 开源100G网卡方案的现状:你其实没多少选择

说句实话,网卡这个领域开源生态并不繁荣。100G商用网卡以Mellanox、Chelsio、Intel为主,驱动是闭源的,寄存器手册也是NDA满天飞,你想在网卡里加一段自定义逻辑,比如精确打时间戳、自定义流表匹配、旁路DMA,基本没戏。FPGA网卡是一条出路,但市面上能买到的FPGA网卡方案,大部分也是绑定厂商私有框架,真正把RTL全开放给你的,数来数去Corundum是这个圈子里绕不过去的一个。

Corundum由Alex Forencich发起,最吸引人的地方在于它不是一个“玩具”项目。它提供了一套完整、模块化的100G以太网MAC/PCS、PCIe DMA引擎、队列管理、以及Linux驱动。这意味着你拿到手的不是一个需要再补几万行逻辑的半成品,而是能跑通TCP/IP协议栈、能跟标准交换机互通的正经网卡。它的BSD许可以及对RTL完全开放的态度,让它成了FPGA网络研究社区里事实上的标配起点。

这套设计支持10G/25G/40G/100G多速率,而且内部高度参数化。核心的MAC和PCIe部分拆得很干净,基础模块是bs Lib那种通用RTL库的风格,很多模块连注释都写得跟教程一样。它的Linux驱动直接把标准网络接口暴露给内核,上层的socket应用完全感知不到底层是FPGA还是ASIC网卡。就冲这一点,它就比那些需要自研整套驱动框架的开源项目省了太多事。

1.2 选VV4而不是官方开发板的原因

Corundum官方示例支持不少Xilinx板卡,比如VCU118、VC709和部分Alveo加速卡。理论上直接用官方板卡最省心,但我选Bittware VV4有自己的考量。

VV4的核心资源非常能打:Virtex UltraScale+级别的FPGA,集成了PCIe硬核,片上逻辑和DSP足够跑100G的完整收发数据通路,板载QSFP28接口和DDR4内存。更重要的是,VV4是一块通用商用板卡,原理图和硬件手册都是完整公开的,这意味着它在移植时几乎不存在“黑盒模块”——所有引脚、时钟分配、电源时序都能查到,适合做深度的二次开发。相比之下,某些商业加速卡把很多底层细节藏起来,想在RTL层面做一些定制就不太方便了。

另一个原因是VV4的板卡定位非常适合做网络研究。它不是为了某个固定云业务设计的,板载资源和对外接口都比较均衡,适合挂到自己实验室的服务器上当开发平台。而且在二手市场,VV4这类老牌FPGA板卡的价格比官方开发板合理不少,对预算有限的团队来说,用商业板卡替代官方开发板跑开源网卡,是一条性价比很高的验证路径。当然,这条路需要付出的代价就是:官方示例用不了了,所有适配工作都得自己来。

2. 动手移植前必须先摸清的板卡底细

2.1 VV4的硬件结构:两个FPGA的板子,谁是主控

先别急着拉代码,第一步是搞清楚你手里的板卡到底长什么样。VV4这板子的硬件架构比较特别,它不是单FPGA设计,而是板载了两片Xilinx的Virtex UltraScale+系列FPGA。这种双芯片架构在高端网络加速板卡上很常见,一片负责跟主机PCIe打交道,另一片专职做数据处理。移植Corundum时,必须明确一个问题:哪片FPGA最终要承载Corundum的整个网卡逻辑?

如果选错了FPGA,后面所有引脚约束和时钟约束全都要推翻重来。从PCIe链路来看,跟主机相连的那个FPGA是必须作为主FPGA的,因为Corundum的DMA和寄存器访问通道都依赖PCIe。另一片FPGA在Corundum这套方案里大概率用不上,最多做旁路数据处理。这里我的建议是:先查VV4的手册确认PCIe x16链路到底接到哪片FPGA的哪个Bank,再把Corundum的顶层设计落到对应的器件上。别想当然地认为第一片FPGA就是主控,有些板卡会把PCIe直接接到编号靠后的FPGA上。

顺便提醒一句,双FPGA板卡上电和复位时序也比单芯片复杂,两片FPGA各自有独立的配置模式、时钟源和复位输入。Corundum的全局复位逻辑通常会假设只有一颗FPGA,所以移植时需要把VV4上主FPGA的复位信号和PCIe的PERST信号对好,否则可能出现PCIe已经枚举成功但内部状态机一直没被释放的情况。

2.2 时钟树:移植中最容易翻车的第一站

硬件板卡移植最容易翻车的不是逻辑代码,而是时钟。Corundum设计里对时钟是“挑食”的,官方示例板卡都是按特定时钟拓扑调好的,换到VV4上,最常遇到的问题就是“看起来时钟频率没错,但GT收发器死活不上线”。

先罗列一下Corundum在运行100G模式时需要的几路时钟。第一路是系统时钟,一般是200MHz,用于PCIe AXI-Lite桥、队列管理器和控制逻辑。第二路是MAC用户时钟,100G模式下的AXI接口位宽是512bit,对应的接口时钟约195.3125MHz,这是用100G线速率除以512bit算出来的——100e9/512=195.3125e6。第三路是100G光口物理层的那路GT参考时钟,标准值通常是156.25MHz。

这三路时钟在VV4板卡上的来源各不相同。系统时钟一般来自板载可编程振荡器,GT参考时钟则被接到主FPGA特定Bank的MGTREFCLK引脚上,MAC用户时钟通常由GT收发器恢复出来的时钟再跨到用户逻辑域。移植时不能只改频率,还要确认时钟信号到底接到了哪些物理引脚上,否则一个BANK号对不上,综合可能能过,但上板跑起来就是全乱。

2.3 对照Corundum的三大时钟需求

我在移植前做了个表格,把自己要的时钟和VV4能提供的时钟一项项对齐,这个表格强烈建议你也做一份:

用途Corundum默认要求板卡实际来源移植动作
PCIe系统时钟200MHz自由运行时钟板载可编程时钟确认引脚,必要时用MMCM分频匹配
MAC用户时钟100G下约195.3MHzGT恢复时钟或独立时钟检查是否可跨时钟域
GT参考时钟156.25MHzQSFP28附近MGTREFCLK引脚与GT位置约束一起核对
用户侧低速时钟通常50~125MHz板载时钟用于I2C、复位等外围逻辑

这份表格在动手改RTL之前一定要拿VV4的原理图逐项核对一遍。尤其是GT参考时钟,它跟GT收发器位置强绑定,你选哪一组QSFP28对应哪一片GT Quad,完全由板卡布线决定。Corundum原版的通用顶层不会知道你VV4的QSFP28接在哪个Quad,这一步就是移植的核心工作量之一,后面第五章节会展开细说。

3. 搭好工程与工具链,别让环境成为第一个坑

3.1 源码获取与固件目录结构

说完理论,进入实际操作。先把Corundum代码拿到手。它的源码托管在GitHub上,直接git clone即可。注意这个仓库用了Git LFS管理部分大型文件,克隆完记得执行git lfs pull,否则后面在Vivado里生成IP时会报一些莫名其妙的文件缺失错误。这是一个很多人一开始没注意、然后排查了半天才发现的坑。

Corundum的FPGA部分目录结构相当规整。核心代码在fpga/mqnic下面,这是网卡主逻辑所在,包含PCIe对接、队列、MAC配置这些模块。fpga/lib则是一些通用基础库,比如AXI、以太网MAC、FIFO这些。每个官方支持的板卡都有一套自己的顶层wrapper和XDC约束文件,目录名一般直接用板卡型号命名。移植到VV4,本质上就是新增一个board目录,把官方板卡的wrapper改造成适配VV4的顶层,再把引脚约束全部替换。

3.2 Vivado版本、Board Files与IP许可

用什么Vivado版本会直接影响移植难度。Corundum官方持续在跟进的版本,我用下来Vivado 2021.1比较稳,很多社区里的移植案例也都是在这个版本上完成的。新版本Vivado也能打开旧工程,但IP核版本升级可能引入额外的兼容问题,如果你的工程里恰好用了某个官方示例IP,升级的时候IP会被自动刷新,刷新完可能需要重新配置。首轮移植我建议保持官方推荐版本,等跑通了再考虑升版本。

VV4这块板卡不一定有现成的Vivado Board Files。Board Files的主要作用是让你在Vivado图形界面里选封装、选引脚配置更方便,但对Corundum这种以脚本和约束文件为主的工程来说,Board Files不是必须的——你完全可以手工创建工程、指定器件型号、再手动加入XDC约束。Bittware更新过VV4的支持包,网上能搜到,但某些旧版本只支持特定Vivado版本,如果要装,记得匹配好。

另外注意Xilinx的IP许可问题。Corundum依赖的以太网MAC/PCS、PCIe硬核这些IP,在UltraScale+器件上基本都是免费内置的,不需要额外购买许可证。但Vivado本身必须是被正常许可的版本,WebPack版能不能支持VU190级别的器件我不确定,我实际用的是完整版。如果你的团队没有Vivado正版授权,这一步提前处理好,不然到了综合阶段卡住很浪费时间。

3.3 先跑仿真验证理解

移植工作开始之前,我强烈建议先花一两天时间跑通Corundum自带的仿真环境。不是为了验证功能——官方代码基本没问题——而是为了让自己彻底理解数据通路是怎么串起来的。你可以打开仿真波形,观察PCIe TLP是怎么变成AXI事务的,队列描述符是如何被搬运到FIFO里的,MAC发送侧又是怎么把AXI数据变成以太网包的。这些理解在接下来改顶层时非常值钱,因为很多引脚命名在去板级wrapper里是跟物理信号直接相关的,如果你不知道它对应逻辑里的哪一环,改起来就是瞎蒙。

Corundum的仿真环境适配了常见的仿真器,Vivado自带的XSim和开源生态的Verilator都能跑。如果你用的是XSim,直接按make脚本执行即可。仿真时重点观察几个关键信号:复位释放的顺序、PCIe的AXI-Lite寄存器能否正常读写、MAC发送FIFO的AXI握手。这些如果通了,基本说明你理解对了整体框架,再进入改板级逻辑就有底了。

4. 第一步移植实操:PCIe与寄存器空间适配

4.1 Corundum的PCIe路径:硬核还是XDMA

移植过程中第一个真正动手的地方是PCIe。Corundum在Xilinx平台上的PCIe实现,依赖的是FPGA里集成的PCIe硬核IP。在UltraScale+器件上,这个硬核集成块能直接产生AXI4和AXI4-Lite接口,Corundum就是靠这套接口把网卡寄存器空间和DMA数据通路暴露给主机的。

这里有一个很多人绕弯路的点:Corundum并没有默认绑定Xilinx的XDMA IP,也就是那个带DMA引擎的闭源NIC。Corundum把DMA引擎做在了自己开源的逻辑里,PCIe硬核IP只负责TLP层和AXI桥接。这意味着你在Vivado Block Design里做PCIe部分时,配置项主要围绕BAR空间、AXI接口宽度、中断引脚来设置,而不是去生成一个完整的XDMA Example Design。

对VV4来说,主FPGA的PCIe硬核位置和引脚在器件上是固定的,你只需要在IP配置里选择对应的GT Quad和链路宽度即可。VV4一般支持PCIe Gen3 x16或者x8,Corundum的数据通路带宽要够,至少配置成x8以上。x4链路跑100G DMA理论上是够呛的,因为PCIe Gen3 x4的理论吞吐只有约32Gbps,根本喂不满100G网卡的收包速率。

4.2 BAR映射与mqnic_core的寄存器改动

PCIe BAR空间是网卡与主机软件交互的窗口。Corundum通常把BAR0作为寄存器空间,映射到AXI-Lite总线上,里面放类似mqnic_core的控制状态寄存器。BAR2作为DMA数据空间,映射到AXI4总线上,用于描述符和包buffer的访问。这个分割是Corundum驱动正常运行的前提。

换板卡时,BAR0的基地址由PCIe枚举时自动分配,RTL侧不需要写死,但BAR空间的大小必须和PCIe硬核的配置一致。如果硬核里把BAR0配成了64KB,而mqnic_core里的寄存器译码逻辑实际访问范围只有4KB,那也不会出大问题——最多浪费一点地址空间。真正要小心的是BAR2这个DMA空间,它的大小直接决定了主机能访问多少DMA缓冲区,你至少要配到4GB以上的64位地址空间,否则大流量下DMA寻址会撞墙。

我第一次移植时就在这里犯过错:参考官方配置把BAR2配成了32位地址空间,驱动加载正常,接口也能起来,但一跑大包iperf就出现卡顿和丢包,查了半天发现是DMA高32位地址没被正确解析。后来把BAR2改成64位地址空间,问题立刻消失。这个细节在官方示例里可能不会踩到,因为官方板卡的驱动和硬件配置是配套的,但你一旦改板卡,PCIe硬核配置里的地址位宽必须跟着板卡DMA能力走。

4.3 用ILA和仿真确认传输通道

PCIe这条链路怎么验证是否真的通了?不要盲目上板打流,那样问题太发散。我的经验是先在Vivado例化一个ILA探针,挂在PCIe硬核的AXI4-Lite接口上,观察主机驱动加载时产生的寄存器读写事务。驱动中对mqnic_core的访问是第一步,如果ILA里能看到写0x0这种reset寄存器的TLP落下来,说明PCIe枚举和BAR映射已经正确,寄存器通路是通的。

接下来验证DMA通道。这时候可以用一个小技巧:在ILA里同时抓取AXI4数据通道和中断输出,然后从主机侧用一个简单的PCIe读写工具,对BAR2地址发起读写。如果数据能完整经过AXI4通道到达板卡侧的FIFO,并且中断能正常拉高,那么DMA数据通路的静态检查就过了。这里不需要真的跑网络流量,纯内存读写验证已经把大部分PCIe适配问题暴露出来了。

5. 硬骨头:GT收发器与QSFP28的物理映射

5.1 100G物理层拆解

PCIe通了只是让板卡“能被主机访问”,真正让Corundum变成网卡的,是光口物理层。这部分也是整个移植里最跟板卡硬件绑定、最不能靠猜的部分。

100G以太网的物理层不是一根线跑100G,而是四条独立收发器通道,每通道25.78125Gbps,合成100G带宽。FPGA里这些高速收发器就是GT,在UltraScale+里是GTY,每个GT Quad包含四路收发器,刚好对应一组QSFP28的四条通道。QSFP28端口的物理连接是固定的,它插到FPGA的哪一组GT Quad、每组GT Quad用哪个参考时钟输入,这些信息只能从VV4的原理图里找。

Corundum官方示例板卡上,这些映射关系已经写好在XDC里了,你不需要关心。但到了VV4上,整个GT映射表就是你的核心工作。你需要打开VV4的原理图,找到QSFP28笼子到FPGA Bank的连线表,记录每一路TX/RX对应FPGA封装的哪个引脚,同时还要确认MGTREFCLK引脚在哪。把这些整理成一张引脚映射表,再换成XDC里的get_ports定位,这一步千万别省略,我见过直接把官方XDC里的引脚名字改成VV4的名字就上板的人,结果是GT位置全错,综合能过但bit文件下载后链路永远无法建立。

5.2 改GT位置约束的正确姿势

GT的位置约束有两种改法。一种是在XDC里用PACKAGE_PIN和LOC直接把收发器引脚定到具体的封装引脚上,另一种是在User Constraint里指定get_cells -hierarchical定位到GT primitive。Corundum这种用IP核分层的设计,最省事的方法是在XDC里约束顶层引脚名,然后让Vivado自动做引脚到GT Quad的路由。

实际操作时我推荐一个顺序:先把QSFP28的TX/RX、参考时钟这些引脚放到XDC中,跑一次综合,看Vivado报出的GT位置分配结果。然后对照原理图检查这些GT Quad是否跟QSFP28的物理连接一致。如果一致,说明布线方向选对了;如果不一致,多半是你某个引脚名写错了或者原理图看错了。这种“先综合后核对”的方式比纯手工改LOC绑定要稳得多,因为Vivado的布局器可能会优化掉一些冗余约束。

这里还想强调一个细节:GT Quad的摆位不是任意的,一个Quad里四路收发器必须来自同一个时钟域,不能把其中两路参考时钟按156.25MHz,另外两路按另一个频率。QSFP28的四条通道必须共享同一个参考时钟资源,否则收发器之间bandwidth不匹配,链路根本建不起来。移植时,一定要确认所有四路TX/RX都在同一GT Quad或者由同一个参考钟驱动的一组Quad内。

5.3 QSFP28管理:I2C、复位、中断与ModPrsL

很多人移植时只关注高速数据线,忽略了QSFP28的管理信号,结果光模块插上去完全没反应。QSFP28模块本身的低速管理接口是一组I2C总线,用于读取模块的EEPROM,比如厂商信息、光功率、温度这些。此外还有几个重要的低速控制信号:ModPrsL表示模块在位,低电平有效;Reset和LPMode分别控制模块复位和低功耗模式;IntL则是模块中断输出。

Corundum内部自带I2C控制器,用来扫描光模块。到了VV4上,你要把这组I2C信号和QSFP28的物理引脚对接上。这里面有个容易忽略的问题:QSFP28的I2C地址可能因为硬件拉高/拉低而不同,默认一般是0x50,但某些板卡会把A0/A1地址引脚接成别的值。Corundum在扫描时会按固定地址去查询,如果你的板卡地址不同,模块的EEPROM读不到,驱动就会报PHY模块不存在。

另外注意复位逻辑的极性。QSFP28的Reset是低电平复位,但很多FPGA板卡上的GPIO输出极性经过反相器,实际拉高才是复位。这种电平极性问题很难从原理图中一眼看出来,需要配合信号实测。我的建议是先在ILA里抓一下几个控制信号的状态,再决定要不要在RTL里加反相逻辑。

5.4 参考时钟来源的选择

GT参考时钟看起来简单,其实是很多移植翻车的地方。100G的GT参考时钟一般是156.25MHz,但不同板卡对这个时钟的处理方式不一样。有些板卡用一颗可编程时钟芯片给GT提供参考时钟,开机后默认输出可能是125MHz,要做I2C配置之后才能切到156.25MHz。如果你忽略了这一步,GT收发器的参考时钟对不上,综合时查不出任何错误,上板后光是时钟恢复就会失败。

VV4的板载时钟方案具体怎么配,需要查手册。有些是可编程时钟芯片在上电后自动加载EEPROM配置到正确频率,有些则需要主机通过I2C去写。我建议在移植初期,先用示波器实测一下GT参考时钟引脚上是否有波形、频率是否对。没有示波器的话,也可以在Vivado的Hardware Manager里看GT的时钟状态寄存器,那里能直接读出来参考时钟锁定状态。这一步验证成本很低,但能省下后面两天瞎折腾的时间。

6. 移植的验收标准与后续路线

6.1 怎么算移植成功

移植这件事不能靠“感觉差不多”来判断,要有一份明确的验收清单。我给自己定的验收标准大致如下,你可以根据自己的需求调整:

验收项通过标准主要排查手段
PCIe枚举主机能看到设备,驱动能加载lspci、dmesg
寄存器访问驱动对BAR0读写无错误dmesg、ILA波形
DMA通路主机与FPGA互传数据正确自定义PCIe读写工具
光模块识别模块EEPROM能被读取ethtool -m
链路建立对端能看到端口upethtool、ip link
收发包正确对打无CRC错包、无丢包ethtool统计、iperf3
线速带宽100G口跑出接近线速iperf3 -u或TCP多流

在这份清单里,前四项属于“板卡适配完成”的范畴,后三项才是真正“跑通网卡”的范畴。第一次移植不建议一上来就追求线速,能把链路建立起来、驱动能识别端口、小流量包不出错,就已经赢了大部分问题。线速优化是后面的事,而且100G线速通常需要调整MSI-X中断、DMA描述符数量、CPU绑核这些参数,这些跟Corundum本身的适配关系不大,更多是主机侧调优。

6.2 我的推进清单

如果你也想复现这次移植,按照下面的顺序推进,能省掉不少弯路。第一步,拉源码,跑通官方仿真,理解数据通路。第二步,建VV4的顶层工程,先用Vivado跑综合,确保器件型号、引脚约束、时钟约束无误,这步只求综合通过,不求上板跑通。第三步,把PCIe硬核配置好,上板验证PCIe枚举;这一步建议用Vivado自带的Hardware Manager直接看PCIe配置空间,不要急着加载Corundum驱动。第四步,把GT和QSFP28的物理约束搞定,上板验证光模块识别和链路建链。第五步,加载驱动,用环回方式验证收发包无误。最后才是对打流量和性能测试。

每个步骤之间留出足够的验证时间。PCIe和GT是整个系统里最复杂的两部分,分别单独调试能大幅降低排错复杂度。如果一上来就把全部模块合在一起,任何一个信号没对,你都不知道是该查PCIe还是该查GT,那种调试体验相当痛苦。

6.3 后续文章要覆盖的内容

这一篇算是一个开头,重点放在了“移植前该想清楚什么”和“硬件层面怎么摸底”上。后面几篇我打算按模块继续拆:PCIe硬核的具体配置流程、mqnic_core里面针对VV4的寄存器适配、GT收发器IP的重建方式、QSFP28 I2C扫描逻辑的具体修改点,以及驱动加载后遇到的各种链路异常。有些坑我自己也在踩,比如双FPGA板卡上PCIe复位和GT复位的时序配合,这类问题光看代码很难想明白,等有了更完整的调试结论再拿出来分享。

按我的经验,这种移植项目最忌讳的就是把所有内容压缩在一篇文章里,写到后面自己都分不清是步骤还是踩坑记录。分篇写虽然看起来慢,但每一篇都能给后来者一个可以照做的完整切片。这篇的“切片”就是硬件架构与时钟、PCIe和GT的整体规划,下一期直接从PCIe生成工程的实际配置开始聊。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询