Zynq-7000 PetaLinux 千兆网卡 Link UP 但无法 Ping 通的终极排查与解决(以 KSZ9031 为例)
文章目录
- [Zynq-7000 PetaLinux 千兆网卡 Link UP 但无法 Ping 通的终极排查与解决(以 KSZ9031 为例)](#Zynq-7000 PetaLinux 千兆网卡 Link UP 但无法 Ping 通的终极排查与解决(以 KSZ9031 为例))
-
- [📌 问题背景与现象](#📌 问题背景与现象)
- [🕵️♂️ 排查全过程(干货预警)](#🕵️♂️ 排查全过程(干货预警))
-
- [第一步:排除最低级的干扰(Windows 防火墙)](#第一步:排除最低级的干扰(Windows 防火墙))
- [第二步:分析 Dmesg,揪出 "Generic PHY" 隐患](#第二步:分析 Dmesg,揪出 "Generic PHY" 隐患)
- 第三步:网络降速测试(定位时序问题的试金石)
- [🛠️ 终极解决方案(只需两步)](#🛠️ 终极解决方案(只需两步))
-
- [步骤 1:在内核中开启特定 PHY 芯片驱动](#步骤 1:在内核中开启特定 PHY 芯片驱动)
- [步骤 2:在设备树中开启 RGMII-ID 并微调皮秒级延迟(核心重点)](#步骤 2:在设备树中开启 RGMII-ID 并微调皮秒级延迟(核心重点))
- [步骤 3:编译与验证](#步骤 3:编译与验证)
- [💡 原理解析:为什么千兆必须要调 Skew?](#💡 原理解析:为什么千兆必须要调 Skew?)
📌 问题背景与现象
在进行 Zynq-7000 自制板卡的网络 Bring-up 时,遇到了一个嵌入式网络开发中最经典的"玄学"问题:
- 使用 PetaLinux 编译系统,从 NAND Flash(或 SD 卡)启动成功。
- 插入网线后,网口指示灯正常闪烁。
- 串口终端输入
ifconfig,网卡(eth0)已分配 IP,且显示 RUNNING。 - 串口内核日志(dmesg)明确打印出:
macb e000b000.ethernet eth0: link up (1000/Full)。 - 致命现象:Zynq 无法 Ping 通直连的电脑,电脑也无法 Ping 通 Zynq,且
arp -a查不到对方的 MAC 地址。
软硬件环境:
- SoC: Xilinx Zynq-7000 (XC7Z020 / XC7Z010 等)
- PHY 芯片: Micrel (Microchip) KSZ9031 千兆 PHY
- 网络接口: RGMII
- 操作系统: PetaLinux
🕵️♂️ 排查全过程(干货预警)
遇到"亮灯但 Ping 不通"的情况,切忌盲目怀疑硬件虚焊。这通常意味着 MDIO 管理接口正常(能读出 Link 状态),但 RGMII 数据通道异常(数据全是乱码被丢弃) 。按以下逻辑排查,可精准定位病根。

第一步:排除最低级的干扰(Windows 防火墙)
很多时候板子其实已经发出了请求,是电脑拒绝响应。
动作: 确保电脑端设置了同网段的固定 IP(如 192.168.0.1),并彻底关闭 Windows Defender 防火墙(专用网络与公用网络均关闭)。同时建议暂时禁用电脑的 Wi-Fi 避免路由冲突。
第二步:分析 Dmesg,揪出 "Generic PHY" 隐患
在 PetaLinux 终端输入:
bash
dmesg | grep -i phy
如果你的输出包含类似以下内容:
Generic PHY e000b000.etherne:03: attached PHY driver [Generic PHY]
⚠️ 结论:这就是导致千兆 Ping 不通的罪魁祸首之一!
Generic PHY(通用驱动)只包含了 IEEE 基础寄存器控制,它能完成自协商(所以能 Link UP),但它不知道如何配置特定厂家的私有寄存器来开启 RGMII 的内部时钟延迟(Delay) 。千兆速率下不加延迟,采样必然全错。

第三步:网络降速测试(定位时序问题的试金石)
千兆(1000M)对 RGMII 时钟(125MHz)的延迟要求极度苛刻,而百兆(100M,时钟 25MHz)容错率极高。
我们在 Windows 电脑的"网络适配器 -> 属性 -> 配置 -> 高级"中,将"速度和双工"强制改为 100 Mbps 全双工 。(或在 Linux 端用 ethtool -s eth0 speed 100 duplex full autoneg off)。
等板子端提示 link up (100/Full) 后,再次 Ping 测试。
🎯 关键结论:如果百兆能 Ping 通,千兆 Ping 不通,100% 证明底层硬件链路和网线没问题,绝对是 PHY 芯片的千兆 RGMII 时钟延迟(Clock Skew)配置错误!

🛠️ 终极解决方案(只需两步)
针对上述排查结果,我们需要在 PetaLinux 中启用专属驱动,并在设备树中精准微调 KSZ9031 的时钟延迟。
步骤 1:在内核中开启特定 PHY 芯片驱动
在 PetaLinux 工程根目录下运行:
bash
petalinux-config -c kernel
依次进入:
Device Drivers -> Network device support -> PHY Device support and infrastructure
找到 Micrel PHYs (或者你实际使用的 Marvell / Realtek),按空格键选中使其前面变成 [*]。保存并退出。
步骤 2:在设备树中开启 RGMII-ID 并微调皮秒级延迟(核心重点)
打开用户设备树文件:
project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
将以太网节点(通常是 &gem0 或 &macb0)修改为如下配置。
注意:KSZ9031 这颗芯片对 PCB 走线极度敏感,除了设置 phy-mode = "rgmii-id" 外,通常必须加入下方的 skew-ps 参数来强行微调发送/接收时钟的皮秒延迟。
devicetree
/include/ "system-conf.dtsi"
/ {
};
&gem0 {
status = "okay";
/* 【核心1】强制开启 RGMII 内部双向延迟 */
phy-mode = "rgmii-id";
phy-handle = <ðernet_phy>;
mdio {
#address-cells = <1>;
#size-cells = <0>;
/* 注意这里的 @3 需要与你实际硬件的 PHY 地址一致 */
ethernet_phy: ethernet-phy@3 {
reg = <0x3>;
device_type = "ethernet-phy";
/* 【核心2】KSZ9031 千兆时序微调专属参数 */
/* 将数据和控制信号的延迟归零 */
txen-skew-ps = <0>;
rxdv-skew-ps = <0>;
rxd0-skew-ps = <0>;
rxd1-skew-ps = <0>;
rxd2-skew-ps = <0>;
rxd3-skew-ps = <0>;
txd0-skew-ps = <0>;
txd1-skew-ps = <0>;
txd2-skew-ps = <0>;
txd3-skew-ps = <0>;
/* 将发送(txc)和接收(rxc)时钟的延迟强行设为 3000 皮秒 (3ns) */
/* 确保时钟采样沿完美落在数据眼图的正中心 */
txc-skew-ps = <3000>;
rxc-skew-ps = <3000>;
};
};
};
步骤 3:编译与验证
保存设备树后,重新编译系统:
bash
petalinux-build
将生成的 BOOT.BIN 或 image.ub 烧录进开发板。
系统重启后,输入 dmesg | grep phy,确认驱动已变为 [Micrel KSZ9031 Gigabit PHY]。
插上网线,执行 ping 192.168.0.1,享受丝滑的千兆网络吧!
💡 原理解析:为什么千兆必须要调 Skew?
在 RGMII 接口中,MAC 和 PHY 之间的数据线和时钟线是同步发出的(即边沿对齐)。
但在接收端要正确采样数据,时钟的跳变沿必须对准数据的正中心。这就要求我们必须在 PHY 芯片内部人为给时钟线加一个大约 2ns 的延迟。
phy-mode = "rgmii":不加任何延迟。phy-mode = "rgmii-id":PHY 芯片内部自动给 TX 和 RX 加固定延迟(比如默认 2.0ns)。
由于不同自制板卡的 PCB 走线长度不同,默认的 2.0ns 可能不够。而 Micrel KSZ9031 的 Linux 驱动支持通过设备树读取 txc-skew-ps = <3000> 等参数,直接写入其底层内部寄存器,从而实现皮秒级的完美时序对齐。这就是为什么上面的几行代码能起到起死回生作用的根本原因。