ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

FPGA四光口以太网方案:AXI 1G/2.5G Ethernet Subsystem主从级联配置实战

FPGA四光口以太网方案:AXI 1G/2.5G Ethernet Subsystem主从级联配置实战 做FPGA网络设备的人早晚会遇到一个问题单网口不够用。我之前做视频采集传输项目时一开始是单光口接入后来客户要求同时支持一路采集、两路转发、一路管理这就得把板卡上的四个SFP光口全用起来。Kintex7 AXI 1G/2.5G Ethernet Subsystem 是Xilinx生态里最成熟的组合之一但四个网口同时工作怎么配时钟、怎么分地址、怎么把数据通路串起来这里面的坑比想象中多。这篇文章是动手向的以一块Kintex7四光口板卡为例子手把手走一遍 AXI 1G/2.5G Ethernet Subsystem 主从级联的完整配置流程。你不需要对这个IP特别熟但至少应该知道 AXI4-Lite 和 AXI4-Stream 的基本概念知道主从指的是发起方和响应方。我会把架构设计、IP参数、时钟复位、总线接线、约束写法、调试方法全部串一遍过程中还会穿插我实际踩过的坑。做完之后你能直接在类似板卡上复刻一套四口以太网方案。1. 项目概述与整体设计思路1.1 为什么选AXI 1G/2.5G Ethernet Subsystem它解决什么问题Xilinx 官方提供的以太网IP有好几类老的Tri-Mode Ethernet MAC、后来的AXI Ethernet、以及2018.x以后主推的 AXI 1G/2.5G Ethernet Subsystem。这个新IP把MAC、PCS/PMA、GT收发器整合成了一个子系统对外只暴露 AXI4-Lite 配置口和 AXI4-Stream 数据口极大减少了MAC层和物理层之间的胶合逻辑。它最方便的地方在于当你用的是 SFP 光模块且协议选 1000BASE-X/2500BASE-X 时整个收发链路不需要外部PHY芯片GT Bank 的收发器直接驱动光模块。这样板子上省了一堆 PHY 和 MDIO 网络软件上也不用折腾 PHY 寄存器只要把 MAC 和 DMA 初始化对数据就能在 AXI 总线上跑起来。四光口方案的实际需求很典型要么做数据采集分发要么做透明交换要么做协议转换。无论哪种本质都是多个网口收发数据统一进DDR再由CPU或者DMA做决策处理。所以这里选择这个IP是合理的官方维护、文档齐全、回环测试方便。1.2 主从级联到底级联什么先把架构想明白很多人一看到主从级联就以为要像菊花链一样把网口串起来其实不是。在AXI语境里主是发起读写的master从是响应读写的slave。AXI 1G/2.5G Ethernet Subsystem 对外有两个维度配置维度Ethernet Subsystem 的 AXI4-Lite 接口是 slave它被 MicroBlaze 或者外部CPU配置。DMA 的寄存器接口也是 slave。数据维度DMA 是 AXI MM master它发起对DDR的读写。Ethernet Subsystem 的 axis_tx 是 slave接收DMA吐出来的数据axis_rx 是 master把收到的以太网帧递给DMA写进内存。所以主从级联指的其实是一个主控CPU通过 AXI 总线管理多个从设备四个Ethernet Subsystem 四个DMA数据通路上DMA各自做masterDDR统一做slave。这个架构里最需要理清的就是谁控制谁和数据往哪走理清了之后整个设计就成功了一半。我之前见过有新手把 axis_rx 直接接到另一个端口的 axis_tx想模拟级联转发这种做法物理上能通但不具备实际意义因为你没法做路由、过滤、速率匹配。正确做法永远是先进DDR再软件决策再发出也就是存储转发架构。1.3 四光口数据通路规划DMA怎么分工四个网口对应四个独立的 Ethernet Subsystem 和四个独立的 AXI DMA。这里的独立非常重要如果只带一个DMA然后用 AXI Stream Switch 去切换四个网口虽然省LUT但同一时刻只能一收一发带宽直接被腰斩而且调试时互相干扰得不偿失。具体分工如下每个 SFP 口对应一个 Ethernet Subsystem 实例eth0~eth3每个实例的 axis_tx/axis_rx 接各自的 DMA。每个 DMA 通过 AXI SmartConnect 连接到同一个 DDR 控制器。MicroBlaze 作为主控通过一个 AXI SmartConnect或者 AXI Interconnect把 AXI4-Lite 总线分发给所有 IP 的寄存器接口。这样做的好处是每个网口收发的数据路径完全独立带宽互不影响排查问题的时候可以单独停掉一路ILA探针可以单独挂在其中一端口上不会因为共享机制把问题搞混。DDR带宽方面四个1G口满速率收发的数据总量是 4 × 125MB/s 500MB/s即使加上MicroBlaze做管理平面的开销对DDR3 1600理论带宽约12.8GB/s来说非常宽裕。如果在2.5G模式下四个口满跑总量是1.25GB/s仍然在DDR3的承受范围内但AXI总线位宽和仲裁策略需要留意后面第四节展开。2. IP配置与时钟复位设计2.1 创建IPVivado里的操作入口打开Vivado工程在IP Catalog里搜索 AXI 1G/2.5G Ethernet Subsystem直接双击添加。需要添加的IP实例包括4个 AXI 1G/2.5G Ethernet Subsystem4个 AXI DMAMicroBlaze作为主控也可以用外部软核或硬核方案2个 AXI SmartConnect一个走配置通路一个走数据通路1个时钟管理Clocking Wizard负责把板载差分时钟转成多路用户时钟IP配置界面看起来选项很多但只要抓住核心那几项其余保持默认即可。Vivado版本推荐2019.1以上老版本这个IP还叫 AXI Ethernet功能类似但寄存器布局有差异。2.2 关键参数速率、物理模式、GT通道以1G光口为例在IP配置界面里主要看这几项Speed Selection选 1Gbps 或 2.5Gbps。四个口可以各自独立选择实际项目中建议统一方便写驱动。Physical Interface选 1000BASE-X光模块直连无外部PHY。如果以后要接RJ45电口才选 SGMII。GT Reference Clock这里选 125MHz这是GT收发器必须的参考时钟频率。不管你跑1G还是2.5G线速率参考时钟都用125MHz内部PLL会自动倍频。Management Interface选 AXI4-Lite。这个接口用来配置MAC和状态寄存器。启用内部回环有一个 Loopback 的配置位第一次上板建议先开 PMA loopback 做自检后面调对端通信再关掉。GT通道的选择要严格对照板卡原理图。四光口的板子每个SFP笼子通常连到FPGA的特定GTX通道上你必须到原理图里找到 SFP0~SFP3 对应的 GTX 位置然后在IP的 GT Selection 里填对。如果填错要么布线报错要么信号完全不通。2.3 时钟树设计别让GT参考时钟背锅多网口最容易翻车的就是时钟。四光口方案里时钟需求是这样的板级给FPGA一个 GT 参考时钟通常是 125MHz 差分时钟接到 FPGA 的 MGTREFCLK 引脚上。四个 Ethernet Subsystem 的 GT 参考时钟最好全部由这一个 125MHz 时钟经过 BUFG_GT 分给四个 IP。不要给每个IP单独引不同的时钟源否则四个口的PCS/PMA频率基准不一致对端交换机收到的每个端口频率漂移都不一样很难排查。配置通路时钟 dclk/s_axi_aclk用MicroBlaze的系统时钟一般100MHz统一供所有Lite接口和DMA寄存器接口。数据通路时钟 axis_clk1G模式下是125MHz2.5G模式下是156.25MHz配合16bit TDATA。DMA 的 mm2s/s2mm 接口时钟直接用DDR侧时钟比如200MHz。实际操作时我习惯把所有时钟在 Block Design 里用 Clocking Wizard 一次生成并把每个Ethernet Subsystem的 axis_clk 连接在对应DMA的 axis 时钟上保证跨时钟域只发生在IP内部。这种一个时钟域里不要混多路数据的原则能帮你在写约束和调试时少掉一半头发。2.4 复位设计原则四个子系统要能独立复位如果说时钟是骨架复位就是神经。Ethernet Subsystem 的复位分两级GT复位gt_rx_reset/gt_tx_reset和MAC/数据通路复位axi_reset。GT复位必须在PCS/PMA之前完成否则内部状态机起不来。多端口设计里我强烈建议给每个Ethernet Subsystem和DMA都单独拉一个复位信号做成一个分组复位控制系统。可以是一个简单寄存器用CPU写一个 bit mapbit0对应eth0的复位bit1对应eth1的复位以此类推。这样调试任意一个端口不用把所有口都重新初始化。我曾经遇到过一个问题四个口同时复位其中一个口永远起不来单独复位它就好了。后来查出来是复位释放瞬间GT参考时钟没有完全稳定四个口同时抢同一个PLL的控制权导致某一个口的初始化时序被破坏。改成独立分组复位之后这个问题再没出现过。3. 主从级联接线实操3.1 AXI4-Lite管理总线接线与地址分配打开 Block Design先把 MicroBlaze 搭好然后添加两个 AXI SmartConnect。第一个 SmartConnect 专门用来分发配置通路MicroBlaze的 M_AXI_DC 口或者 M_AXI_DP接进去master侧接8个slave接口eth0_lite、eth1_lite、eth2_lite、eth3_lite以及 dma0_reg、dma1_reg、dma2_reg、dma3_reg。地址分配可以这样规划以64K对齐为例外设基地址大小用途eth0_lite0x44A0000064K以太网0 MAC配置eth1_lite0x44A1000064K以太网1 MAC配置eth2_lite0x44A2000064K以太网2 MAC配置eth3_lite0x44A3000064K以太网3 MAC配置dma0_reg0x44A4000064KDMA0 描述符控制dma1_reg0x44A5000064KDMA1 描述符控制dma2_reg0x44A6000064KDMA2 描述符控制dma3_reg0x44A7000064KDMA3 描述符控制这个分配的好处是每个设备独占一个64K地址窗口驱动代码里可以用基地址偏移的方式访问所有寄存器操作统一为写偏移地址。Bad Address 异常发生时也能根据地址快速判断是哪个外设没有配置好。MicroBlaze本身也需要一段指令数据和DDR空间建议从0x00000000分配BRAM做BootLoader然后把应用放到DDR里比如0x80000000之后。DDR的地址由 MIG 控制器决定我的做法是在地址编辑器里手动分配不依赖Vivado自动布局因为自动布局偶尔会把 lite 和 DMA 的地址交错写驱动容易踩错。3.2 AXIS数据通路与AXI DMA的连接配置通路接好之后数据通路就简单了但最容易被忽视。以 eth0 为例eth0 的 m_axis_rx数据从MAC来接到 dma0 的 S2MM 接口DMA写DDR。eth0 的 s_axis_tx数据发往MAC接到 dma0 的 MM2S 接口DMA从DDR读。dma0 的 M_AXI_SG 和 M_AXI_MM2S/M_AXI_S2MM 全部通过第二个 AXI SmartConnect 接到 DDR 的 S_AXI 接口上。第二个 AXI SmartConnect 的master侧挂的是四个DMA的M_AXIslave侧只挂一个DDR控制器。SmartConnect 的仲裁策略我建议在 Address Editor 里把每个 DMA 的带宽请求设置为高并且打开 Enable QoS 给每个 DMA 的 AR/AW 通道设置一个优先级避免多口同时突发时互相饿死。还需要注意一个细节Ethernet Subsystem 的 axis_tx/axis_rx 接口位宽默认是8字节64bit但实际能否正确传输取决于 TUSER 信号是否能跟随数据包。AXI Ethernet Subsystem 的 axis_tx_tuser 带有用户控制信号默认 Keep 信号就够了。如果在接DMA时发现 Keep 或 Last 信号被截断多半是在 Block Design 里没有把 TUSER/TKEEP 打勾连接一定要确认所有 tuser/tkeep/tlast 信号都已经连上。3.3 引脚约束与综合实现Block Design连好之后剩下就是引脚约束。四光口的基本引脚包括GT 收发器差分对sfp0_rxp/sfp0_rxn、sfp0_txp/sfp0_txn依次到sfp3。GT 参考时钟板级125MHz差分时钟引脚。SFP 控制引脚包括 TX_DISABLE、LOS、MOD_DEF0、MOD_DEF1、MOD_DEF2 等具体看原理图。XDC 里 GT 引脚约束模板如下引脚号按实际板卡替换set_property PACKAGE_PIN AH10 [get_ports {sfp0_rxp}] set_property PACKAGE_PIN AH11 [get_ports {sfp0_rxn}] set_property PACKAGE_PIN AJ10 [get_ports {sfp0_txp}] set_property PACKAGE_PIN AJ11 [get_ports {sfp0_txn}] set_property IOSTANDARD LVDS [get_ports {sfp0_rxp}] set_property IOSTANDARD LVDS [get_ports {sfp0_rxn}] set_property IOSTANDARD LVDS [get_ports {sfp0_txp}] set_property IOSTANDARD LVDS [get_ports {sfp0_txn}]需要特别强调GT 差分引脚不要用普通 IO 标准必须用 LVDS 或类似差分标准。参考时钟的约束同理。SFP控制引脚是单端信号一般用 LVCMOS18 或 LVCMOS25具体看FPGA bank供电电压不要把电压设错导致烧模块。综合实现时Vivado 会自动处理 GT 相关的时钟约束通常不需要手动 create_clock。但多个IP共享同一个GT参考时钟时最好在约束文件里显式声明参考时钟避免综合工具把它当成异步时钟处理产生出乎意料的时序路径。3.4 软件驱动初始化顺序IP硬件连接全部完成后软件初始化顺序也很有讲究。我的经验是严格按这个顺序配置 MIG 和 DDR 控制器等待 calibration done。把四个 DMA 的复位和四个 Ethernett Subsystem 的复位全部释放。等待每组中断或状态寄存器确认 MAC 核已退出复位。逐个配置 MAC 的速率1G/2.5G设置 MAC 地址打开 TX/RX 使能。初始化 DMA 描述符队列并把 DMA 的 S2MM 和 MM2S 通道 Select 好。先开 DMA 的 S2MMRX通路再开 MM2STX通路后开 MAC 的 TX/RX。顺序不能乱尤其不要一开始就打开 MAC 的 TX否则DMA没有准备好数据来了没地方放直接造成 RX overrun 中断风暴。4. 调试与问题排查实录4.1 光模块链路起不来先查GT参考时钟这是四口方案里最经常出现的问题。现象是 ILA 里看 Ethernet Subsystem 的 status 寄存器 link 位一直为0或者 PCS/PMA 报 loss-of-signal。第一步永远是确认GT参考时钟有没有正常送到IP。在 Vivado 里打开 hardware manager看 PRB 和收发的 init_done 信号或者直接看 ILA 抓 gt_rx_status 的状态。如果 init_done 一直拉低八成是参考时钟有问题。用 ILA 抓一下 MGTREFCLK 的 frequency_counter 寄存器能直接读出参考时钟频率。我遇到过最坑的一次原理图里 SFP0 和 SFP1 的参考时钟走了一根共享的差分对切换开关需要 FPGA 输出一个 GPIO 来控制 MUX。结果 GPIO 初始值默认选择了另一个时钟源导致所有光口都没信号。排查到最后一层才在硬件手册小字里看到这个MUX。这事告诉我们拿到新板子第一件事把原理图里所有和 GT 时钟相关的 MUX/放大器/电平转换都过一遍再谈配置。另一个常见情况是SFP模块的 TX_DISABLE 引脚没有拉低或没有控制。大部分SFP模块要求TX_DISABLE为低电平时才允许发光。如果这个引脚悬空或者默认上拉模块就一直处于静默状态对端当然收不到光。Vivado 约束里记得把 TX_DISABLE 这个信号引出并处理不能图省事不接。4.2 回环测试正常但对外不通内部回环PMA loopback能通过说明 MAC、PCS、GT 收发链路本身没问题数据路径是通的。但对外通信时经常遇到灯亮了但 ping 不通的情况。这种问题我用两条思路排查速率不匹配对端交换机或者另一块板卡是 1G而你这边配的是2.5G光模块协商不出来物理层就断了。先用 serial terminal 或 ILA 抓 status 寄存器里的速度字段确认当前速率。编码方式不匹配1000BASE-X 和 SGMII 的自动协商机制不同如果对端用的是 SGMII 交换机而你这边配的是 1000BASE-X会一直 idle 但建立不了 link。需要改成 SGMII 模式或者强制1000BASE-X。还有一种情况是光模块本身只支持 1.25G 线速率你却把它用到 2.5G 模式模块直接不工作。选模块前看一眼规格书里的速率等级不要默认光模块都能扛2.5G。4.3 多网口同时跑带宽和仲裁问题四个口同时跑的时候最容易出问题的是 AXI SmartConnect 的仲裁策略尤其是在 2.5G 模式下。四个网口的总线吞吐量加起来是1.25GB/s虽然DDR3带宽够用但AXI总线是分时复用的当一个DMA长期占用 burst 通道不放其他DMA的 response 延迟就会显著增大表现出来就是某一端口丢包率突增。解决方案有两个层面。硬件上在 SmartConnect 里把每个端口对应 DMA 的 QoS 优先级配成一样的权重并打开 Burst 转换 让短突发合并成长突发减少总线占用次数。软件上把 DMA 描述符队列长度加长比如默认64个描述符改成256个或512个给 DMA 更大的缓冲来吸收总线的瞬时抖动。还有一个我在实测中确认过的技巧让每个端口的 RX 描述符放在不同的 DDR bank 或不同的 memory region减少多个 DMA 同时访问同一页面导致的 bank 冲突。在 Zynq 上还能用 OCM 来放 descriptor但在 Kintex7 上只能靠 DDR 地址交错效果也还不错。4.4 复位时序与初始化僵局与复位相关的僵局典型表现是第一次复位能工作但软件软重启之后某个端口起不来。查到最后基本都是复位释放时机的问题。AXI 1G/2.5G Ethernet Subsystem 的完整初始化需要等待三个事件GT 的 txresetdone/rxresetdone、PCS/PMA 的 align_status、以及 MAC 的 reset_done。这三个信号任何一个没有拉高就急着开DMA后续行为都是不可预期的。所以我在驱动里加了个三阶段确认逻辑第一步软件复位IP第二步轮询 status 寄存器确认 GT 完成第三步等待 rx_los 拉低、align_status 拉高第四步才使能 MAC TX/RX。这个顺序在四端口下运行时尤其有效因为四个GT通道都是独立初始化的完成时间各不相同。另外复位信号本身最好用同步复位且不要直接用板级复位按钮接一路给所有IP。用 MicroBlaze 的 GPIO 输出多个复位信号并且每个复位信号都接入一个 UtilsFF 的同步器能显著降低复位释放时亚稳态的概率。FPGA 里的复位同步问题处理不好就是偶发性宿命处理好了就是一次过。最后一句话这四个光口的配置流程我前前后后调了两周。后来每次做新板子我都先把时钟树画清楚、把地址映射表定下来、把主从关系写清楚再开 Vivado。All of this说起来是技术做起来是耐心。如果你在做类似多网口方案碰到什么问题欢迎按文里的排查思路走一遍大概率会比我那两周顺利得多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进