基于Corundum的FPGA 100G网卡移植实战:从选型到PCIe枚举

发布时间:2026/9/26 1:25:56
基于Corundum的FPGA 100G网卡移植实战:从选型到PCIe枚举 1. 项目缘起为什么偏要用FPGA做100G网卡先交代一下我手里的活一批要做高速数据采集和预处理的小项目之前一直用商用100G网卡加通用服务器。商用卡的性能确实没得说但一旦遇到自定义报文格式、硬件级过滤、高精度时间戳和多队列调度就特别别扭。后来我把目光转向了开源FPGA网卡方案Corundum又配了一块基于Intel Arria 10的Bittware VV4板子折腾了小半年总算把100G链路跑通。这个系列就是记录整个移植过程第一篇重点讲选型判断、架构拆解和工程准备的思路适合有FPGA基础、准备自己动手做100G网卡或数据面加速的工程师参考。1.1 商用NIC用得好好的为什么还要自己折腾如果你只是跑iperf商用100G网卡又稳又快真没什么可抱怨的。但需求一变就难受了想在网卡层面做自定义流表、想在收包路径上加硬件标记、想给每个流单独打时间戳还想让多个DPDK进程共享队列而不互相干扰。这些需求在商用卡上要么做不到要么只能在驱动层绕绕来绕去性能就飘了。更麻烦的是很多高端卡的关键特性按模块授权License一年一续价格比板卡本身还贵用起来束手束脚。FPGA方案的好处是网卡行为完全由RTL定义数据面怎么切分报文、中断怎么合并、队列怎么映射全部自己说了算。代价是难度高尤其是100G这个量级。数据路径宽、时钟高一个跨时钟域的细节没处理好长时间运行时就会出偶发丢包排查起来非常酸爽。所以我劝一句这类工作不要盲目跟风适合有FPGA经验、同时有网络协议背景的团队。1.2 Corundum到底给了我们什么Corundum最核心的价值不是“给你一块能用的网卡”而是一套可复用的“NIC in RTL”资产。我当初评估它主要看四点数据面完整MAC、FIFO、DMA引擎、描述符环全部开源没有黑盒多队列和可编程中断是原生特性MSI-X、RSS都支持这对高性能应用非常关键有PTP时钟体系报文收发时间戳能做得比较准后续做时间同步应用省很多事驱动配套齐全Linux下的mqnic驱动、DPDK PMD都有验证链路能直接打通。当然开源不等于拿来就上板。PCIe硬核的例化、SerDes到光模块的物理链路、时钟树和复位逻辑、引脚和时序约束这些板级适配工作还得自己做。Corundum把通用逻辑部分做得很干净真正费力的是平台相关层。1.3 为什么是Bittware VV4这块板选Bittware VV4有几个实际原因。第一它用Intel Arria 10 GX逻辑资源、PCIe Gen3 x8和高速SerDes这几个维度比较均衡第二板上有两个QSFP28笼子意味着未来可以从100G扩展成2x100G或者拆成多个25G通道第三当时很容易从渠道拿到社区里也有不少项目在用踩坑时能找到人问。不过VV4毕竟不是为Corundum设计的开发板所以移植中会遇到所有“平台不匹配”问题PCIe参考时钟从哪个引脚进、SerDes的TX/RX怎么映射到QSFP、板级复位极性对不对、JTAG链上还挂着什么其他器件。这些问题光看数据手册处理不完必须结合原理图一项项核对我后面会专门讲这部分。在立项时我们还算过一笔带宽账这个得提前说清楚100GE净负载是100Gbps换算成字节是12.5GB/s而PCIe Gen3 x8的实际有效带宽大约只有7.9GB/s。所以如果VV4的PCIe接口是Gen3 x8这台网卡是跑不满100G线速的。这个限制不解决后面所有高性能目标都要打折。好在我们的业务模型是“收多发少”或“发多收少”定向流量下还能接受。如果你的场景要求192Gbps双向线速第一件事就是换Gen3 x16或Gen4 x8的板卡没有商量余地。2. 读懂Corundum的骨架数据面与控制面是两套体系移植Corundum的第一道坎不是代码问题而是理解它的分层。很多第一次接触的朋友容易犯一个错把整个仓库当成一个大工程去编译结果报错一堆连问题出在哪都搞不清。2.1 顶层模块划分mqnic_core与mqnic_pcieCorundum主体RTL可以按两层拆解。底层是mqnic_pcie这类平台包装模块负责把厂家PCIe IP包装成统一的寄存器接口和DMA接口再往上是mqnic_core它定义了网卡应有的内部结构收发引擎、描述符缓存、完成队列、中断控制器、以太网MAC、PTP时钟等。具体到某个厂家的FPGA你要做的工作是写一个自己的顶层把厂家PCIe IP的AXI输出连进mqnic_pcie再把MAC侧连到厂家SerDes转出的数据线上。Corundum做这层抽象非常到位PCIe IP在不同厂家之间差异巨大而以太网和DMA逻辑相对通用移植时主要工作在厂家专用层通用核心基本不动。这也是我敢选Corundum的原因之一它把最容易被厂商锁死的部分隔离得很好。2.2 收发数据流与描述符环形队列对应用层来说最重要的概念是描述符环形队列。收包路径大致是MAC收到帧写入RX FIFODMA引擎根据软件预先填充的RX描述符把数据搬进主机内存再通过完成队列通知驱动发包路径反过来驱动填写TX描述符DMA引擎从主机内存取数据交给MAC发送。这套机制决定了性能上限。Corundum把描述符深度、缓存大小、队列数量都做成了可配参数你在例化时可以按需调整。我强烈建议第一版先跑默认配置单个DMA通道、单队列、关闭RSS先把链路跑通再逐步增加队列。原因很简单多队列会同时把MSI-X中断数和缓存深度拖起来任何一个参数变化都可能引入新的时序或资源问题不要在验证阶段就给自己上难度。2.3 时钟域AXI总线时钟、MAC时钟、PTP时钟三者不能混很多移植问题都出在时钟上Corundum核心里有三个时钟域必须重点关注AXI DMA时钟通常由PCIe用户时钟导出Arria 10 Gen3 x8配置下常见为250MHz以太网MAC时钟Corundum的100G MAC数据路径是512bit接口按64b/66b编码后的线速率103.125Gbps换算纯MAC接口时钟大约在195MHz到201MHz这个量级但实际工程里为了容纳控制字和行间间隙配合PCS gearbox后经常抬高到320MHz附近。确切数值必须看你选的PCS配置和代码里的参数不能照抄别人的约束PTP时钟推荐独立晶振或独立PLL导出它直接决定时间戳精度。这里有个常见的坑有些板子为了省事把MAC时钟和PCIe用户时钟混用短时间也能工作但PTP精度会飘长时间跑还会出现偶发的时序违例。我在VV4上坚持三套时钟分开生成前端用专用PLL给以太网组PCIe用户时钟单独引出PTP再用一个低抖动PLL。布线虽然麻烦一点但后续做时间戳应用会省很多事。2.4 移植前需要对照的模块清单模块作用移植时需要关注的点mqnic_core网卡核心逻辑一般不改动mqnic_pciePCIe包装层必须与厂家IP对接mqnic_eth以太网MAC接口适配需匹配SerDes/PCSmqnic_port单端口收发引擎参数化配置mqnic_dmaDMA引擎时钟、缓存深度参数mqnic_intr中断与MSI-X依赖PCIe IP能力ptp_clock时间戳时钟需独立时钟输入这张表是我自己整理的和仓库目录不是严格一一对应但按这张表去看代码思路会清晰很多。刚开始不要一头扎进每个模块的寄存器定义先把模块边界画清楚把数据流的走向弄明白。3. 移植前的地图作业VV4板级资源盘点第二步是把VV4这块板彻底搞清楚。不要急着建工程先把板卡原理图、引脚约束文件打开逐项核对这一步就是所谓“地图作业”。3.1 板上FPGA型号与资源我手里这块VV4主芯片是Arria 10 GX系列具体型号以板卡丝印为准。Arria 10的资源量对于跑一个100G网卡核心来说相当充裕实际综合下来Corundum 100G核心大概占20%到35%的逻辑资源。如果你只做基本NIC功能资源不是瓶颈瓶颈一定在时钟布线和SerDes通道规划上。需要提醒的是不同批次的VV4可能搭配不同封装或不同等级FPGA引脚分配不能直接抄别人的工程最好以随板提供的参考工程为基准再核对你的板卡版本。这一步看似笨但能从源头避免“原理图明明连了综合却报引脚不存在”这种尴尬。3.2 PCIe硬核与参考时钟Arria 10带硬核PCIe IPGen3 x8配置下参考时钟一般是100MHz。你要确认板上这颗100MHz晶振经过的缓冲器、扇出和引脚位置并在Quartus的PCIe IP配置里按原理图选对参考时钟引脚。很多人容易把“参考时钟信号进了FPGA”等同于“PCIe IP能锁定”其实还得确认PLL REFCLK源、上电时序和PERST#信号是否合规。我习惯用示波器量一下PERST#和REFCLK的时序关系再继续别省这一步。如果板上有PCIe Switch还要关注JTAG链和PERST的排布。VV4作为端点卡相对简单但主机BIOS兼容性问题仍然可能遇到典型表现就是配置完成后PCIe设备反复消失这个放到第6章细说。3.3 QSFP28与100G PHY链路100G以太网在VV4这类板卡上走的是QSFP28常见实现是4x25G NRZ即对应SerDes的四条TX和四条RX差分对。Corundum的100G MAC在逻辑上输出512bit数据流物理侧还需要PCS和PMA。在Arria 10里这可以是Native PHY IP或者干脆让SerDes做裸直通把PCS放在FPGA逻辑里。这里有个容易误解的点多写几句如果把SerDes配置成带完整PCS的PHY IPMAC看到的接口会变成XAUI或XLGMII风格而Corundum的MAC默认期望的是直接数据流接口。所以我在VV4上的方案是“外置SerDes只做SerDesPCS放到FPGA逻辑里MAC用Corundum自带的100G MAC”两边接口直接对齐。这也是为什么在引脚约束里要单独处理SerDes的TX/RX而不是像普通PHY那样配一组MDIO管理接口就完事。3.4 复位、JTAG与配置Flash板级细节里最容易翻车的是复位。VV4上可能同时存在FPGA配置复位、PCIe PERST#和板级上电复位极性和时序各不相同。Corundum内部有异步复位同步释放的逻辑但要求外部复位信号在PCIe用户时钟稳定之后再释放。我的经验是额外引一个拨码开关复位到FPGA引脚调试初期即使自动复位有问题也能一键重置。JTAG建议走板载的USB-Blaster链启动前检查链上是否还串着板载管理MCU。如果串着烧写时要选中链上指定器件否则会报JTAG ID mismatch。配置Flash方面我建议先用JTAG直接加载SRAM对象文件调试确认一切稳定后再写进配置器件避免反复擦写把板子弄成砖头。4. 搭建工程从Corundum例程到VV4适配做好准备现在开始搭工程。这一步的顺序很关键会直接决定后面调试的顺畅程度。4.1 拿到源码后第一步做什么先从官方仓库拉代码重点确认子模块一并拉全Corundum依赖verilog-ethernet等子模块直接下载zip特别容易漏编译时会报找不到eth_mac_10g这类诡异错误。接着我建议先把仓库自带的仿真环境跑一遍用Verilator或Icarus做一个基础回环仿真确认代码在逻辑层能工作再考虑上板。很多人跳过仿真直接上板遇到问题后无法判断是代码逻辑问题还是平台适配问题白白浪费大量时间。4.2 Quartus工程与IP配置VV4是Arria 10我直接用Quartus Prime Pro。新建工程后选好器件把Corundum的RTL源文件按目录添加进去。比较关键的是生成PCIe Hard IPIP名称Arria 10 PCIe Hard IP链路配置Gen3 x8AXI接口位宽512bit对应PCIe用户时钟在250MHz附近中断方式打开MSI/MSI-X相关选项。如果Quartus版本太新或太旧IP版本和工程TCL可能出现兼容性警告。我的做法是先用板卡厂商提供的工程模板建底再手动把Corundum源文件加进去这样引脚和IP版本都跟着板卡走出问题最少。别直接在空工程里从零开始板卡商的工程里已经帮你排掉了大量坑。4.3 以太网数据路径的局部替换在VV4上我把Corundum核心例化在一个自定义顶层vv4_top.v里。这个顶层干三件事例化PCIe IP把其AXI接口连到mqnic_pcie例化SerDes收发器让4x25G数据流进入FPGA内部的PCS生成独立的MAC时钟和PTP时钟。有的朋友觉得直接改Corundum自带的example更快但我建议自建顶层保持Corundum原核不动。这样一来以后升级Corundum版本时只需要对比顶层差异不用在核心源码里打补丁。我的源码目录结构大致是corundum/ rtl/ lib/ fpga/ custom/ vv4_top.v vv4.qsf vv4.sdccustom/目录专门放板级相关文件不会污染主仓库提交进Git也方便其他人复现。4.4 引脚分配和时序约束引脚分配优先沿用板卡商给的QSF文件再补充SerDes和时钟引脚。时序约束至少包含以下几项PCIe参考时钟和PERST#的input约束以太网SerDes方向上的RX/TX时钟约束PTP时钟约束建议设置uncertainty所有跨时钟域异步信号加set_false_path或伪路径。如果在时序报告里看到MAC时钟路径失败不要急着加综合优化选项先检查PLL分频倍频配置是否合理。100G MAC的512bit数据路径在Arria 10上要做到较高频率是有挑战的PLL配置稍有不同时序余量就会差很多。我第一版就吃了这个亏后面第5章详细讲。5. 第一次综合/实现遇到的真实问题按真实踩坑顺序讲几个Corundum加VV4组合下很典型的问题这些问题在Xilinx平台上未必会遇到但用到Arria 10时很容易撞见。5.1 PLL与时钟约束报错第一次综合Quartus直接报PLL输入时钟引脚冲突。原因是我在TCL里既保留了板卡工程的REFCLK定义又把Corundum的PTP时钟绑到了同一个PLL的另一个输入导致两个IP争同一个物理引脚。解决方法是把PTP时钟从独立的高精度晶振引脚引入并单独放在一个PLL上。这个问题的根因就是时钟规划没做干净和代码本身没关系。所以我还是强调工程启动前先画一张时钟树草图标清楚每个时钟从哪里来、到哪里去、由哪个PLL生成再开始写约束。5.2 资源占用与布线失败实现阶段遇到过布线失败问题集中在MAC 512bit数据路径和DMA缓存之间。查下来发现是我把AXI接口位宽改成了512bit但DMA缓存深度还按原来的低带宽场景配置导致寄存器扇出过大。把缓存深度参数调回与512bit匹配的值再对关键路径加max_fanout约束布线就顺畅了。这类问题最忌讳直接删时序约束换一时的编译通过一旦时序问题留到上板长时间运行或温度升高后就会随机丢包。先怀疑参数配置再优化具体路径才是正路。5.3 用Signal Tap验证复位和时钟等编译通过后我习惯先在Signal Tap里配置几个探针clk、clk_ptp、rst以及PCIe用户状态寄存器。目标不是抓实时数据而是确认上板后时钟真在跑、复位确实释放了。别小看这一步很多“上板无反应”的问题八成是复位没释放或者PLL没锁定在Signal Tap里一眼就能看出来。Arria 10的Signal Tap使用和早期Cyclone系列有些差异但基本原理一样。提前把探针信号加到工程里重新综合一次比上板后反复改线要高效得多。6. 上板清单与PCIe枚举这一阶段的验收标准在第一篇里我们的目标不是跑数据而是在主机上看到PCIe设备被正常枚举。这一步做到就说明移植的主干是通的。后面的驱动、打流、调优留给系列第二篇。6.1 硬件连接与固件加载先把VV4插到服务器PCIe x16槽位连接QSFP28光模块或DAC线对端设备可以先不管等优化阶段再接。确认PCIe辅助供电接好风扇正常。用JTAG把编译出的SRAM对象文件加载进去观察配置完成LED。这里有一个我踩过的坑主板BIOS没开启Above 4G Decoding导致MMIO空间不足配置完成后PCIe设备一直不出现。如果你在BIOS里看到这个选项建议直接打开。对FPGA网卡这类需要大块MMIO空间的设备这个开关非常重要。6.2 lspci看到设备才算真正的第一步成功加载完成后在Linux下执行lspci如果输出里出现你要的厂商ID和器件ID说明PCIe硬核已经接通03:00.0 Ethernet controller: Device 1234:5678 (rev 01)接着执行lspci -vv确认LnkCap和LnkSta都是8GT/s x8。这里有个容易误解的地方链路显示Gen3 x8不代表配置空间访问一定成功你还得真正读写BAR空间才算数。我习惯再用setpci读写一个已知寄存器验证比如把某个版本寄存器读出来和RTL里定义的版本号比对。6.3 常见失败枚举不到、链路没up枚举不到的大方向有三个一是PCIe硬核IP参数不对比如把Endpoint配成了Root Port二是复位时序不对要检查PERST#和REFCLK关系三是电源或散热不足100G核心功耗不低没加散热时跑几分钟就会频率降级表现就是PCIe链路随机掉或枚举不稳定。第三个问题尤其容易被忽略VV4是高密度板卡务必在机箱风扇风流正常的环境下调试不要裸板跑满负载。如果设备枚举到了但lspci -vv显示链路只有Gen2也要查一下PCIe IP里的Max Payload Size和Max Read Request Size配置有时主机BIOS和FPGA端参数协商不一致链路会以较低速率运行。6.4 下一阶段预告PCIe枚举成功后下一步就是加载mqnic驱动、把网口UP、跑回环和iperf打流。这里面会涉及驱动编译、固件接口、收发队列调优等内容放到系列第二篇展开。本阶段先把“硬件和平台跑通”这个里程碑守住能通过lspci稳定识别反复重启不掉线就已经比多数移植尝试前进了一大步。最后说一点个人体会移植Corundum这类项目真正花时间的不是连线而是把板上每个信号的作用搞清楚。VV4的板级细节、Arria 10的PCIe配置、Corundum的分层结构任何一个环节一知半解后面都会以更诡异的方式找回来。建议每解决一个问题都顺手记录现象、原因、改了什么、验证方法。这套记录到最后就是你自己的移植手册比任何官方文档都好用。第一篇就先到这里把地基打好第二篇再聊驱动和打流。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询