Zynq-7000 PetaLinux 千兆网卡 Link UP 但无法 Ping 通的终极排查与解决(以 KSZ9031 为例)

文章目录

  • [Zynq-7000 PetaLinux 千兆网卡 Link UP 但无法 Ping 通的终极排查与解决(以 KSZ9031 为例)](#Zynq-7000 PetaLinux 千兆网卡 Link UP 但无法 Ping 通的终极排查与解决(以 KSZ9031 为例))
    • [📌 问题背景与现象](#📌 问题背景与现象)
    • [🕵️‍♂️ 排查全过程(干货预警)](#🕵️‍♂️ 排查全过程(干货预警))
    • [🛠️ 终极解决方案(只需两步)](#🛠️ 终极解决方案(只需两步))
      • [步骤 1:在内核中开启特定 PHY 芯片驱动](#步骤 1:在内核中开启特定 PHY 芯片驱动)
      • [步骤 2:在设备树中开启 RGMII-ID 并微调皮秒级延迟(核心重点)](#步骤 2:在设备树中开启 RGMII-ID 并微调皮秒级延迟(核心重点))
      • [步骤 3:编译与验证](#步骤 3:编译与验证)
    • [💡 原理解析:为什么千兆必须要调 Skew?](#💡 原理解析:为什么千兆必须要调 Skew?)

📌 问题背景与现象

在进行 Zynq-7000 自制板卡的网络 Bring-up 时,遇到了一个嵌入式网络开发中最经典的"玄学"问题:

  1. 使用 PetaLinux 编译系统,从 NAND Flash(或 SD 卡)启动成功。
  2. 插入网线后,网口指示灯正常闪烁。
  3. 串口终端输入 ifconfig,网卡(eth0)已分配 IP,且显示 RUNNING
  4. 串口内核日志(dmesg)明确打印出:macb e000b000.ethernet eth0: link up (1000/Full)
  5. 致命现象: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 = <&ethernet_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.BINimage.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> 等参数,直接写入其底层内部寄存器,从而实现皮秒级的完美时序对齐。这就是为什么上面的几行代码能起到起死回生作用的根本原因。

相关推荐
lsh曙光2 小时前
延时at指令和定时cron指令
linux·服务器·网络
圆山猫2 小时前
[Virtualization](四):Linux KVM/RISC-V 的 vCPU 运行路径
java·linux·risc-v
似的8353 小时前
一步一步学习使用FireMonkey动画() 使用TAnimator类创建动画
linux·学习·nginx
我不管我就要叫小猪4 小时前
嵌入式Linux----网络通信
linux·运维·服务器
泡沫冰@5 小时前
ECS 的介绍和使用
linux·服务器·网络
姜太小白5 小时前
【Linux】df -h 卡住问题的通用排查与解决方案总结
linux·运维·php
fengyehongWorld6 小时前
Linux 终端快捷键
linux·运维
哎呦喂我去去去6 小时前
C#实现屏幕墙:同时监控多个电脑桌面(支持Windows、信创Linux、银河麒麟、统信UOS)
linux·windows·c#
easy_coder8 小时前
Linux LVM 知识文档
linux·运维
小小的木头人8 小时前
Ubuntu 使用 udev + systemd + UUID 实现 USB 硬盘自动挂载
linux·运维·ubuntu