
前段时间调一块 RK3588 板子的网络整整折腾了一个星期才收干净尾巴。板子原来用的是 RTL8211F 这颗瑞昱的千兆 PHY在 RK3588 方案里非常常见评估板、核心板、各种量产板都在用。这次因为供货和 BOM 成本的原因我把默认的 RTL8211F PHY 换成了另一款兼容的千兆 PHY型号我就不点名了下面的记录里就叫它 PHY_X。换之前我想得很简单同样是 RGMII 接口、同样挂 MDIO 总线、同样工作在千兆模式设备树里把 PHY 型号相关的字段改一改应该很快能跑通。结果从硬件检查、设备树配置到内核识别再到最终的应用层 UDP 通信验证每一层都给我“惊喜”。这篇文章就是这次 RK3588 网络调试的现场笔记我会把换 PHY 过程中踩到的坑、每一步排查的思路、以及最后沉淀下来的调试套路全部整理清楚。内容覆盖面比较广从 PHY 外围电路到设备树 phy-mode再到内核 phylib 驱动和 UDP 抓包验证都会涉及适合正在 RK3588 或其他平台做网络调试、准备替换 PHY 的嵌入式软硬件工程师参考。1. 换PHY别急着动软件硬件差异才是第一大坑1.1 pin-to-pin兼容不等于外围电路一致很多替换 PHY 的坑在动手改设备树之前就已经埋下了。RTL8211F 之所以在 RK3588 方案里这么流行除了稳定性好之外还有配套的参考设计非常成熟网上随手就能找到原理图。当你把这个位置换成一款新 PHY 时最危险的直觉就是“既然 pin-to-pin 兼容那我原理图不用动直接换芯片就行”。实际上就算引脚定义完全一致PHY 芯片内部的默认状态、外置电阻的 strap 逻辑、上电复位的要求都可能不一样。我这次就吃了一个小亏RTL8211F 默认的 PHY 地址是 0x01这是由它的 PHYAD0/PHYAD1 引脚外围电路决定的。换上去的 PHY_X 默认地址也是 0x01表面看没问题但它的 strap 电阻接法跟 RTL8211F 参考设计不完全一样——它对 PHYAD0 引脚的上拉/下拉电平判定阈值更敏感沿用原板子的 4.7kΩ 电阻值时地址能识别出来但在高低温边缘会出现 MDIO 地址读取不稳定的情况。这种问题最坑人因为它不是完全不通而是“时好时坏”。所以换 PHY 的第一步不是去翻设备树而是先把新 PHY 的手册翻开逐项核对这几类硬件配置MDIO 地址 strapPHYAD0/PHYAD1/PHYAD2 等引脚的上下拉方式决定了 PHY 在 MDIO 总线上的地址设备树里的 reg 必须和它一致。复位引脚极性绝大多数 PHY 是低电平复位但也有少数芯片对复位脉冲宽度有额外要求。时钟输入方式PHY 是使用外部 25MHz 晶振还是由 MAC 侧直接输入参考时钟或者由 PHY 自己输出时钟给 MAC。延时配置方式RGMII 的 TX/RX delay 是靠外部电阻配置还是靠 PHY 内部寄存器配置默认值是什么。电源供电要求核心电压、IO 电压是 2.5V 还是 3.3V内部 LDO 是否使能。建议把这两颗 PHY 的数据手册的“Strapping Options”“Recommended Circuit”“Delay Configuration”三部分放在一起对照。这一项功课做好后面能少走一大半弯路。1.2 时钟、复位、延时这些“看不见”的参数RTL8211F 和新 PHY 之间真正容易出问题的不是电源和地而是三个“看不见”的参数参考时钟、复位时序、RGMII 延时。先说时钟。RGMII 接口在千兆模式下TX 时钟一般是 125MHz由 MAC 侧给到 PHY也就是 GTX_CLKRX 时钟由 PHY 恢复出来给回 MAC。但很多 PHY 芯片内部还需要一个参考时钟源常见的是外接 25MHz 晶振。RTL8211F 的参考设计里晶振的负载电容取值、起振电路参数都是经过验证的换一颗 PHY_X 后如果它的晶振驱动能力、反馈电阻推荐值不一样就会出现一个很隐蔽的现象PHY 能上电、能扫描到 MDIO 寄存器但是网络协商不稳定插上网线时偶尔能 link 上千兆一会儿又掉到百兆。用示波器看晶振引脚波形幅度可能只有正常值的一半。复位时序也是老坑。有些板子的 PHY 复位引脚直接连到 SoC 的 GPIO软件在设备树里配了 reset-gpios但是 reset-assert-us 和 reset-deassert-us 两个参数是从旧项目照抄过来的。RTL8211F 的上电复位时间可能在 10ms 以内就能完成初始化而 PHY_X 手册要求复位释放后至少等待 50ms 才能开始 MDIO 通信。如果照旧参数只等了 10ms内核 phylib 在 probe 阶段访问 MDIO 时PHY 内部还没准备好就会读到全 F 的 PHY ID导致驱动加载失败网口直接不认。这时候表现出来的是“同样的内核、同样的设备树换了 PHY 后 eth0 就消失了”非常容易让人怀疑是器件质量问题或者焊接问题。延时这个更不用说。RGMII 接口为了实现简单布线标准里规定了要用延迟来补偿数据和时钟的偏斜。RTL8211F 的参考设计里往往会在 PCB 上预留延时电阻的位置或者在设备树里使用 rgmii-id 让 PHY 内部打开 delay。新 PHY 的 delay 默认策略很可能不一样这直接导致后面设备树里 phy-mode 的配置不能照搬。我的建议是在动手写设备树之前先用示波器量一下 MAC 侧 RXC 和 RX_CTL 之间的相位关系再回头决定用哪种 delay 组合而不是一个个试。2. 设备树改不对网口就是“点不亮”2.1 MDIO地址和phy-handle的匹配RK3588 的设备树里以太网控制器一般长这样以 GMAC1 为例gmac1 { status okay; phy-mode rgmii-id; phy-handle phy0; pinctrl-names default; pinctrl-0 gmac1_miim gmac1_tx_bus2 gmac1_rx_bus2 gmac1_rgmii_clk gmac1_rgmii_bus; mdio { compatible snps,dwmac-mdio; #address-cells 1; #size-cells 0; phy0: ethernet-phy1 { reg 1; reset-gpios gpio4 RK_PB7 GPIO_ACTIVE_LOW; reset-assert-us 10000; reset-deassert-us 50000; }; }; };这段配置里mdio 子节点下的 ethernet-phy1 中的 reg 1就是 PHY 在 MDIO 总线上的地址。RTL8211F 默认是 1所以原来的设备树里写的是 1。PHY_X 如果出厂默认 strap 是 0或者板子为了避开地址冲突改成了 3那这个 reg 必须跟着改否则内核 phylib 去地址 1 读 PHY ID读回来全是 0xFF就会报 PHY 不存在。还有一点很容易忽略如果 MDIO 总线上挂了不止一颗 PHY或者有一颗备用的 PHY、交换芯片等器件它们可能占据了别的 MDIO 地址。新 PHY 的 strap 地址如果不小心和别的器件冲突也会导致 probe 失败。判断方法很简单Linux 启动日志里搜索 eth0 或者 mdio 相关字段看有没有类似“Micrel KSZ9031”或“Realtek RTL8211F”的 PHY 识别记录。如果没有或者识别到的是一个奇怪的 ID优先检查 PHY 地址和 strapping。另外我调试时习惯在启动后看这几个路径ls /sys/bus/mdio_bus/devices/ cat /sys/class/net/eth0/phy_address ethtool eth0如果 phy_address 读出来是 0x1f 或者大于 31说明 MDIO 读写异常多半是地址问题或 PHY 未复位。2.2 phy-mode四种RGMII模式怎么选RGMII 有四种常见的 device tree 配置rgmii、rgmii-id、rgmii-txid、rgmii-rxid。它们的区别在于 TX 和 RX 方向的内延时由谁提供。rgmii不加任何内部 delay数据线和时钟之间的偏移调整完全靠 PCB 走线长度或外部电阻实现。rgmii-id同时打开 RX 和 TX 方向内部 delay。rgmii-txid只打开 TX 方向内部 delay。rgmii-rxid只打开 RX 方向内部 delay。RTL8211F 在老项目中常用 rgmii-id。换到 PHY_X 后如果它的默认 delay 策略不一样这行配置就可能出问题。最典型的表现是link 能协商上速率显示 1000Mbps但 ping 不通或吞吐很低。这是因为时钟采样沿和数据沿没有对齐MAC 收到的数据是“歪”的。我这次踩坑的经历很有代表性刚换上 PHY_X 时我先用 rgmii-id结果 link 正常ping 网关延迟忽高忽低从 1ms 跳到几百毫秒iperf3 测吞吐只有几十 Mbps。后来查手册发现 PHY_X 在 TX 方向默认已经打开了内部 delay设备树里再用 rgmii-id 就会把 TX 方向的延时重复叠加等于延迟过头了。把 phy-mode 改成 rgmii-rxid 后吞吐立刻恢复到接近线速。实用调试建议是不要固守旧配置先看 PHY 手册里的 delay 寄存器默认值。如果手册里没有明确写就按“先 rgmii-id不行换单方向再不行换成无 delay”这个顺序去试。每改一次配置都要重新验证两个指标link 是否稳定协商到千兆、大包 ping 和吞吐是否正常。不要只看 ping 通就算过一定要用 iperf3 或者大包压力测试确认时序裕量足够。2.3 复位时序和时钟配置别照抄设备树里的 reset-assert-us 和 reset-deassert-us 是很多人容易忽略的地方。默认值 10ms/50ms 不一定是错的但换 PHY 后一定要重新对着手册确认。我这次把 deassert 时间从 20ms 调到了 50msPHY 识别率明显提升说明旧参数在这个 PHY 上确实不够。另外RK3588 的 GMAC 外设时钟也需要检查。DTS 里 ethernet 节点的 assigned-clock-parents 和 assigned-clock-rates 会影响 MAC 侧生成 125MHz TX 时钟的能力。如果这部分配置有问题就算 PHY link up数据也发不出去。调试中如果发现 TX 方向完全没波形可以先查一下 clk_summary 里 gmac 相关时钟是否正常cat /sys/kernel/debug/clk/clk_summary | grep gmac比较直观的现象是某些板子为了兼容多颗 PHY会在 DTS 里配置不同的 pinctrl导致 GMAC 时钟脚没有正确复用这种情况靠改 PHY 配置永远修不好。3. 内核识别、链路测试到UDP调试一条链路拆到底3.1 PHY驱动部分先把“识别”弄稳RK3588 平台的内核通常已经配置了非常丰富的 PHY 驱动。RTL8211F 有专门的 realtek 驱动支持所以原来板子的网络非常省心。换到 PHY_X 后内核 phylib 能不能正确匹配到驱动取决于内核里有没有对应 PHY 的驱动以及 PHY_ID 匹配表有没有包含这颗芯片。如果内核已经支持 PHY_Xdmesg 里会出现类似识别到的 PHY 驱动名称如果内核里没有它的专属驱动Linux phylib 会退回到 Generic PHY Driver。通用驱动不是不能用但有些 PHY 的特殊寄存器配置比如特定的 delay 配置、EEE 节能模式不会在通用驱动里自动初始化这可能会导致一些莫名其妙的问题。排查 PHY 是否被内核正确识别通常看这几个信息dmesg | grep -i -E eth|mdio|phy ethtool eth0 cat /sys/bus/mdio_bus/devices/*/phy_id如果 ethtool eth0 能正常显示速度、双工、自动协商等参数说明 phylib 已经成功驱动了 PHY如果报错 “Cannot get device settings: No such device”并伴随 mdio 读取失败就要回到地址和复位检查。关于 PHY 驱动还有一个小建议如果条件允许尽量不要长期依赖 Generic PHY Driver。可以对比一下新 PHY 与 RTL8211F 的寄存器差异看是否需要专门的内核配置项。比如在 menuconfig 里把 PHY 相关组件打开或者在设备树的 PHY 节点里指定 compatible确保内核能用最稳定的路径驱动它。这个动作在量产前做掉能避免后续现场调网络时反复试错。3.2 从链路层到应用层经典两段式验证很多朋友踩坑之后容易慌一上来就用网络调试助手发 UDP 包发现收不到就乱改。我的调试习惯是严格遵守两段式验证先验证链路层再验证应用层。链路层不通应用层怎么调都是白搭。链路层验证的固定动作ethtool eth0 # 确认 speed/duplex/link ok ip link show eth0 # 确认 UP ping -c 100 -s 1400 对端IP # 大包测试 iperf3 -c 对端IP -t 30 # 验证吞吐其中 ping 大包是为了制造边界压力如果只有小包能通、大包全丢通常就是时序问题或者 MTU 问题这时回到 phy-mode 去调整 delay。iperf3 的吞吐测试能直接反映 TX/RX 方向的健康程度如果单向吞吐很低也可以帮助定位 delay 方向。链路层验证通过之后再做应用层 UDP 验证。我在 Windows 上习惯用网络调试助手在 Linux 板子上则直接用 nc# 板子 A 上监听 nc -u -l 6666 # 板子 B 上发送 echo hello | nc -u 板子A的IP 6666如果两边在同一网段A 能收到消息说明整条物理链路和协议栈工作正常。如果收不到消息先用 tcpdump 确认包是否到达网卡tcpdump -i eth0 udp port 6666如果在 tcpdump 里能看到包但 nc 收不到那就是防火墙或者用户态程序的问题如果 tcpdump 里完全看不到包说明底层链路还有问题回到链路段继续查。这个分界点能帮你快速缩小排查范围。3.3 PHY寄存器速查与回环测试当链路层表现异常时最有效的工具不是换线、换交换机而是直接操作 PHY 寄存器。下面几个寄存器是调试中最高频用到的寄存器地址名称作用0x00BMCR控制复位、自协商开关、loopback、速度/双工强制0x01BMSR读取 link 状态、协商能力、扩展寄存器是否存在0x04ANAR本端自协商能力通告0x05ANLPAR对端自协商能力判断协商速度和双工0x091000BASE-T Control千兆模式的 master/slave 配置等0x0A1000BASE-T Status千兆协商结果、master/slave 状态我在调试 PHY_X 时就用到了 0x00 寄存器的 loopback 功能。思路很简单把 PHY 配置成内部回环模式然后从 MAC 侧发数据。如果回环模式下 MAC 的发送统计和接收统计都在增长说明 MAC 到 PHY 之间没有问题故障定位到对端链路或者应用层。回环测试可以通过 mdio-tools 或 devmem 直接操作寄存器也可以临时改驱动代码来触发但不建议在正常产品里长期开启回环模式。这一层一旦确定了剩下的事情就简单很多MAC 到 PHY 没问题就看 PHY 到变压器、连接器、网线的链路PHY 到 MAC 有问题就检查 RGMII 时钟和数据线的时序。千万不要在没有数据支撑的情况下盲目换代码那样只会把问题搞得更复杂。4. 常见问题速查与现场排查套路4.1 五个高频“换PHY后遗症”及对应排查这次换 PHY 遇到的问题我整理成了下面这张表基本覆盖了同类场景下最常见的情况现象可能原因排查方向eth0 不存在dmesg里MDIO读不到PHYPHY地址 strap 不一致、复位时序不足、供电异常核对PHYAD strap、试增大reset-deassert-us、量电源和晶振link 反复 up/down复位时间不够、PHY电源纹波大、MDIO读写不稳定延长deassert时间、检查3.3V/1.0V纹波、示波器抓link信号只能协商到100Mbps千兆握手失败、RGMII时钟异常、线缆质量问题用千兆线直连确认、看PHY 0x09/0x0A寄存器、检查TXC走线link up但ping不通phy-mode的delay配置不对、MAC时钟未生成尝试rgmii-id/txid/rxid组合、查clk_summary能发不能收/能收不能发单向delay错误、RGMII RX方向数据采样失败重点调整rgmii-rxid/txid分别测TX/RX吞吐第一行是我这次遇到的首要问题eth0 直接消失查到最后就是 phy 地址 strap 和旧板子的参考设计有差异。第一第二行现象不同但根源往往都在硬件的复位和时钟上排查时可以先从这两项入手。4.2 我给现场调试定的固定顺序踩了一周的坑之后我给自己定了一个固定的换 PHY 调试流程之后再做类似改动效率明显提高硬件核对新 PHY 手册的 strap 配置、复位、时钟、延时默认值逐项和原理图对照。上电抓基础信号示波器量参考时钟波形、PHY 复位释放时间、电源上电时序。扫描 MDIO 地址确认内核能否在期望地址读到合法 PHY ID。确认 PHY 驱动匹配dmesg 和 ethtool 确认 phylib 正常驱动新 PHY。调 phy-mode delay从 rgmii-id 开始用大包 ping 和 iperf3 验证定位最合适的组合。链路层压力测试确认长时间大流量下 no error、no drop。应用层 UDP 验证使用网络调试助手或 nc 做双向 UDP 收发确认用户态功能正常。这套顺序的关键是每一层都“钉死”了再往上走。我见过很多同行是在第 5 步还没做完的时候就开始怀疑应用层甚至怀疑 RK3588 整个 GMAC 有问题结果折腾半天最后发现只是 phy-mode 少了个 rxid。调试网络这种模块最忌讳跳层一层层查最省时间。这次换 PHY 给我的最大体会是PHY 这种“外围小芯片”换起来没那么简单但也没有那么神秘。它的核心就在四个字——时序、地址。地址错了MDIO 读不到设备时序错了link up 也一样丢包。只要把新 PHY 的数据手册当回事把设备树里的 phy-mode、MDIO 地址、复位参数都当成“需要重新验证的变量”而不是从旧项目里继承的正确答案整个调试过程会清晰很多。最后再分享一个实际经验每次修改完设备树 phy-mode 或 PHY 寄存器配置后不要只 ping 几个包就判定 OK至少跑一轮 30 秒以上的 iperf3 双向吞吐再手动插拔几次网线确认 renegotiation 正常。网络问题最大的特点就是“间歇性、偶发性”验证不充分很容易在量产出货后暴雷。希望这篇记录能帮你少踩两个坑。