
做嵌入式网络设备这些年我几乎每个项目都要跟 switch 和 PHY 芯片打交道。从最早的百兆工业网关到后来的千兆核心板甚至带 SGMII 扩展口的平台链路不通、速率协商异常、随机丢包、MDIO 读写失败……这类问题踩过太多次了。每次排查到最后本质都在于对 PHY 和 switch 这两类芯片的“脾气”不够了解。所以我想把这几年在调试和选型上的经验沉淀下来一期一期写透这一篇先讲整体架构、PHY 基础调试和接口时序顺带把选型思路梳理一遍。这篇内容适合三类人看一是刚接手嵌入式网络设备、面对 MAC/PHY/switch 关系还没完全理清的驱动工程师二是做硬件评估和器件选型的硬件工程师三是做系统集成、需要快速定位“网口为什么不通”的全栈开发。我会尽量用大白话讲清楚原理再给可直接照着查的排查流程和寄存器操作方法。1. 先理清架构MAC、PHY、Switch 到底各管哪一段很多新手一上来就对着芯片手册看寄存器结果越看越乱。我建议先搞明白一条网络数据从 CPU 出来到网口之间到底经过哪些“关卡”然后再决定去调谁。这就像寄快递MAC 是写地址、贴面单的人PHY 是把你快递搬上货车、按交通规则上路跑的货运司机switch 则是分拣中心——把不同目的地的货转到正确车道。链路出问题你得先分清楚是面单写错了、司机开错路了还是分拣中心贴错标签了。1.1 三类常见架构和它们的调试复杂度从芯片拓扑上看嵌入式网络设备基本逃不出下面三种架构。第一种是 SoC 内置 MAC外部接一颗独立 PHY。CPU/MAC 通过 RGMII 或 RMII 与 PHY 相连PHY 再经网口变压器到 RJ45。工业控制板、家用网关最常见也最好调因为 PHY 寄存器标准和规范非常透明几乎每一家 PHY 的 0/1 号寄存器含义都是通用的。第二种是 SoC 通过 SGMII/SerDes 接一颗独立 Switch 芯片Swicth 芯片自带多个 PHY 口对外。典型场景是核心交换板、视频传输设备、带多网口的路由器。这里调试关键在 switch 芯片的初始化——SMI/MDIO 接口管理内部寄存器、VLAN 配置、CPU 端口收发包路径难度比第一种高一截。第三种是集成度更高的 SoC内部直接把 MAC、Switch、PHY 全做一起对外只出网口。这种对开发者最友好但一旦出问题芯片内部寄存器黑盒程度高反而更难排查选型时得特别看重原厂驱动和文档的完整度。我自己最常做的是第二种。因为它的灵活性最大端口数量、速率、PHY 增益都可以自主控制也是调试坑最多的地方。1.2 调试链路里的那几道“关卡”把抽象的网络模型落到具体调试路径上一条链路通常要过这些关Linux 驱动和设备树匹配要确保 MAC 驱动认到对应接口PHY 芯片的复位时序和上电时序要正确否则芯片根本没起来MDIO/MDC 总线通信正常驱动才能读写 PHY/switch 的寄存器PHY 自协商和链路建立确保物理层速率、双工协商成功MAC 与 PHY 之间接口模式RGMII/SGMII和时钟延迟要匹配最后才是数据面转发VLAN、CPU 端口、MAC 地址表逐一验证。每一关都会把问题放大。设备树里一个phy-mode写错可能让你在“链路起来了但没有流量”的坑里卡一整天PHY 的 strap 管脚配置错可能让 MDIO 怎么都读不到正确 ID。我这种“先分层再定位”的思路能帮你把问题快速压缩到某一层而不是在整条链路上瞎猜。2. PHY 芯片基础调试先让物理层“活过来”很多人调 PHY 的第一步就是读写寄存器但我劝你先做三件事确认供电和时钟、确认复位释放、确认 MDIO 能通。这三件没过后面全是幻觉。PHY 芯片本质上是一个带有数字管理接口的模拟前端芯片它内部有 DSP、ADC/DAC、PLL对电源纹波和时钟稳定性极其敏感。2.1 MDIO/MDC 读不到寄存器先查这 5 处我统计过MDIO 读写失败90% 不是 PHY 本身坏了而是管理接口的外围条件不对。按概率排序依次是 PHY 地址 strap 管脚配置冲突、MDIO 上拉电阻缺失或偏小、MDC 时钟频率太高导致时序裕量不足、PHY 复位引脚被拉低未释放、IO 电压域不匹配比如 PHY 是 3.3V IOMAC 侧是 1.8V中间电平转换没做好。实际操作时我建议在 Linux 启动早期先用简单粗暴的方式验证 MDIO 总线是否通。在设备树里把对应的 MDIO 总线节点使能后通过/sys/bus/mdio_bus/devices目录能看到 PHY 设备这才是第一步。如果设备节点都没出现就需要检查硬件连接和 strap 配置。内核里读写 PHY 寄存器最常用的是mii-tool或ethtool。前者偏老但查看基本 link 状态很快后者在 2.6.39 之后的内核里基本是标配。我给你一段在多款平台上都验证过的操作流程# 查看 eth0 的 PHY 在 mdio 总线上的地址 ethtool eth0 # 直接读取 PHY 的寄存器0x00 是控制寄存器0x01 是状态寄存器 mii-tool eth0 --phy_reg0x00 --phy_addr1 mdio-tool eth0 1 0x00如果手头没有现成工具直接用 devmem 读 CPU 内部 MDIO 控制器的寄存器也可行但不同 SoC 寄存器布局差异大适合现场应急不适合写进文档。我更喜欢用mdio-tool这类通用工具因为可以快速判断读回的 bit 是否正确。2.2 基础寄存器0x00 和 0x01 一定要吃透IEEE 802.3 规定 PHY 的基本寄存器无论哪家芯片0x00 是控制寄存器0x01 是状态寄存器这是所有 PHY 调试的起点。0x00 里最重要的位是 bit15软件复位和 bit12自协商使能、bit13速率选择、bit8全双工模式。把 0x00 写成 0x8000 会触发软件复位很多寄存器会回到默认值。如果确认某个 PHY 配置“写不进去”先怀疑是不是软件复位没等完成就又写了。0x01 里注意 bit2 是 link 状态bit5 是自协商完成标志。如果读出来这些位总是不对而 MDIO 通路又没问题那大概率是 PHY 的供电或时钟有问题。实测过一个项目PHY 的 25MHz 晶振虚焊MDIO 完全正常但 link 永远起不来读状态寄存器全是 0就是时钟“带病工作”导致 PHY 内部 PLL 没锁住。2.3 复位时序与上电顺序别让 PHY “带病启动”PHY 芯片的复位有两种硬件复位RST 引脚和软件复位寄存器 bit15。我见过不少设计PHY 的 RST 引脚直接被拉低等系统起来后才释放结果会错过 PHY 在 strap 管脚上的采样窗口。PHY 通常在上电或复位释放时会采样特定管脚的电平来决定 PHY 地址、接口模式、时钟方向等关键配置。如果复位释放时序不对PHY 内部采样到错误的 strap 值后面驱动怎么写都是错。建议做法是在原理图设计阶段就把 PHY 复位引脚交给 SoC 的一颗 GPIO 控制并留 RC 延时。软件侧在驱动加载之前至少等待 10ms 再访问 PHY 寄存器如果是硬件复位释放后建议再延时 2ms再去做软件复位。Linux 的 PHY 驱动框架里phy_reset()做了大部分事但前提是复位 GPIO 正确配置在设备树里。mdio0 { ethernet-phy1 { reg 1; reset-gpios gpio0 14 GPIO_ACTIVE_LOW; reset-deassert-us 10000; }; };这个节点里reset-deassert-us设为 10000 微秒意思是复位释放后等待 10ms。这个小参数我调过很多次对于一些国产 PHY这个时间要拉到 50ms 才稳定最好在验证阶段多试几个值。3. RGMII / SGMII 接口调试MAC 和 PHY 之间最容易扯皮链路建立通常不慢麻烦的是“建立了却跑不起来”或者“速率上不去”。这些情况八成出在 MAC 与 PHY 之间的接口配置上而不是 PHY 对外链路本身。3.1 RGMII 时钟延迟一个绕不开的坑RGMII 是一种源同步接口时钟信号和数据信号一起从发送端发出。为了满足接收端的建立/保持时间RGMII 标准要求数据相对于时钟有约 2ns 的延迟。这个延迟可以由 MAC 提供TX 侧也可以由 PHY 提供RX 侧也可以由 PCB 走线长度差提供。Linux 设备树里你常看到的phy-mode rgmii-id意思就是 TX 和 RX 的延迟都由 PHY 内部完成rgmii-txid指只有 TX 内部延迟rgmii-rxid指只有 RX 内部延迟rgmii则是什么延迟都不加全靠 PCB 等长和走线处理。实际调试中如果发现系统起来后 CRC 错误很多或者大包丢包明显先别怀疑 PHY直接用ethtool eth0 -S查rx_crc_errors。如果 CRC 错误数持续走高基本就是 RX 时钟延迟不对。我在一块四层板上遇到过一模一样的问题PHY 百兆一切正常千兆却过不了压力测试最后在设备树里把rgmii-id改成rgmii-txid才解决。这个“改个字符串就能救命”的问题原理在于很多国产 SoC 的 MAC 已经内置了 TX 延迟而 PHY 又默认开启 RX 延迟两边叠加就出现了时序裕量不足。建议内核调试时把一个 PHY 的延迟组合全部试一遍然后做双向大包 ping 和 iperf 测试以误包率和吞吐为准。3.2 SGMII 与 SerDes 模式IP 核与 PHY 联调最容易翻车SGMII 是串行接口线速 1.25Gbps实际承载 1000Mbps 数据。它没有像 RGMII 那样复杂的时钟延迟问题但模式配置——MAC 模式还是 PHY 模式——非常容易搞反。热词里提到“sgmii ip 核与 phy 芯片一起使用时,应配置成 mac 模式”这个说法非常正确也是我踩过最深的一个坑。FPGA 内部的 SGMII IP 核与外部 PHY 芯片对接时通常要求 IP 核工作为 MAC 模式外部 PHY 工作在 PHY 模式即 PHY 侧自动协商并建立链路MAC 侧以固定速率收发。如果两边都配置成 MAC 模式链路层数据包格式会冲突表现为“link 起来了但收发全是错包”有时候连 link 都不稳定。类似问题也会出现在 SoC 的 SerDes 控制器上很多 SoC 的 SerDes 可以配置为 PCIe、SATA、SGMII、1000Base-X 等模式配置错位不光没链路还可能烧 PHY 的输入级。选型时务必确认 SoC SerDes 支持的协议列表并对齐 PHY 的接口标准。SGMII 调试时我还会检查参考时钟的方向。通常由 MAC 提供 125MHz 参考时钟给 PHY也有 PHY 自带晶振的这时候需要确认 PHY 是否工作在主时钟还是从时钟模式。参考时钟倒了SGMII 一样起不来。3.3 link up 但无流量从双工和流控查起“link up but no traffic”是我在社区里被问得最多的问题没有之一。排查顺序我固定是这么一套先确认速率和双工是否一致。用ethtool eth0看Speed: 1000Mb/s, Duplex: Full如果 PHY 自协商出全双工MAC 侧却固定成半双工就会出现单通甚至完全不通。再查流量控制 pause 帧设置部分 switch 芯片默认开启 flow control但 MAC 侧没开在高压场景下会表现为“速度慢到像死了”。然后检查 VLAN。如果你用的是带 VLAN 的 switch 芯片CPU 口的默认 VLAN 配置不对数据帧就会被丢弃或打上错误的 VLAN tag。最常见的现象是tcpdump能看到收包但应用层收不到因为驱动在收包路径上把 VLAN 帧丢了。最后再回头看 MAC 地址表。有些 switch 芯片默认关闭地址学习功能或者 CPU 口没加入转发矩阵导致 PHY 口收到的帧没有转发到 CPU 口。这一步排查需要用到 switch 芯片的寄存器读写工具我后面专门讲。4. Switch 芯片初始化从“裸芯片”到“可用交换机”独立 switch 芯片的调试和 PHY 完全不同。PHY 芯片基本是“插上就能用”switch 芯片则像一个“没有操作系统的路由器”所有转发行为都靠初始化寄存器。厂商给的 demo 代码通常很长但核心步骤就那么几个。4.1 最小可工作初始化流程我在多个平台Marvell、Realtek、国产盛科等上的经验是switch 初始化按这个顺序来成功率最高先检查 strap 管脚配置确保芯片的启动模式、PHY 基地址、CPU 端口编号和你的设计一致。然后通过 SMI/MDIO 接口读取芯片 ID 和版本寄存器确认 MDIO 通路没问题。接着做一次软复位等待芯片完全启动这个等待时间要看 datasheet有的要 200ms 以上。再设置 CPU 端口包括端口速率、双工、帧格式是否接受 VLAN tag并确保 CPU 端口加入默认 VLAN。然后把每个用户端口使能设置端口速率、双工、流控。最后配置默认 VLAN通常所有端口都加入 VLAN 1并设置 CPU 端口为 tagged 或 untagged。每做完一步读对应状态寄存器确认。很多 switch 芯片会提供一个“端口状态寄存器”里面包含 link、speed、duplex、tx/rx 计数比如 Realtek 的 RTL8367 系列0x0000开始是各端口状态读起来非常直接。# 假设 switch 的 SMI 地址是 0x05通过 mdio 访问其寄存器 mdio-tool eth0 5 0x0000 # 读到的是端口0的link状态和速率这里有个经验写 switch 寄存器时一定要在修改前把原值读出来很多寄存器是“读改写”的直接写会清掉其他 bit 的配置导致莫名奇妙的功能异常。4.2 CPU 端口与 VLAN数据上不来先查 VLANCPU 端口是 switch 与 SoC 通信的“大门”。有些 switch 芯片的 CPU 口是独立的 SerDes/SGMII有些是 RGMII。不管哪种CPU 口必须参与 VLAN 转发否则数据进不了 CPU。我做视频传输设备时最经典的一个坑是摄像头接 switch 的 port1SoC 接 CPU 口但 VLAN 配置只让 port1 和 port2 互通CPU 口没加入。结果就是网络抓包能看到 port1 进来的广播帧但 switch 不往 CPU 口转发SoC 永远收不到完整数据流。后来在初始化代码里把 CPU 口加入 VLAN 1 并设置为 tagged 或 untagged立即正常。调试 switch 转发问题时我强烈建议打开镜像功能mirror。它可以把某个端口的收发包复制一份到另一个端口让你用一个普通网卡就能抓到 switch 内部的真实报文流转。很多 switch 的寄存器手册会把 mirror 配置写得比较分散但只要找到port mirror control和mirror port两个寄存器基本就能搞定。4.3 吞吐与丢包问题从错误计数和流控入手吞吐上不去我会先用 switch 自带计数器区分方向。如果是 ingress入口丢包看是不是总线上有错误帧被丢弃如果是 egress出口丢包则可能是出口带宽不够或者对端流量控制没配合好。很多 switch 芯片支持在每个端口上单独统计 CRC 错误、跑短帧、超长帧等。如果某个端口 CRC 错误极多怀疑对象通常是 PCB 走线、变压器、RJ45 座质量或 PHY 芯片配置。不是 switch 芯片本身的问题不要一开始就怪芯片。流量控制也要留意。默认情况 switch 芯片的 flow control 可能是打开的在满负载时对端不响应 pause 帧就会持续丢包。如果数据面是 UDP 视频流我通常直接关闭 flow control改为应用层做丢包容忍效果往往更好。5. 选型要点别只看“速率越高越好”调试经验和选型经验是互补的。很多难调的板子根源在选型时没把边界条件想清楚。我给出自己长期使用的 PHY 和 switch 选型思路框架。5.1 选型前先问 7 个问题端口数需求一个 PHY 还是多个 PHY还是直接选多口 switch速率档位百兆、千兆、2.5G。百兆和千兆的 PHY 在封装和 PCB 上差异巨大接口类型RGMII、RMII、SGMII、QSGMII。要和 SoC 或 FPGA 的接口匹配供电域3.3V 还是 1.8V 的 IO内部 LDO 是否够用工作温度工业级 -40~85℃ 还是商用 0~70℃软件支持Linux mainline 是否直接支持PHY 驱动是否开源供货和备选pin-to-pin 可替代的国产型号有哪些第二供方是谁。5.2 关键参数逐项拆解功耗这一项很多人忽略。4 口千兆 switch 芯片满负荷跑起来功耗可能到 1W 以上在无风扇设备里是笔不小的发热账。选型时看 datasheet 的“典型功耗”还不够要看“最大功耗”并加上 20% 散热裕量。时钟方案PHY 通常需要 25MHz 晶振switch 芯片可能要求 25MHz 或 50MHz 参考输入。晶振精度至少 ±50ppm工业级最好 ±25ppm。用到以太网同步或 PTP 的话时钟精度要求会严格得多普通晶振的 100ppm 偏差可能导致时间同步误差不可接受。寄存器兼容性如果你是替换现有方案那寄存器级兼容比什么都要紧。有些标称 “pin-to-pin 兼容” 的国产 PHY寄存器乱写一通原厂软件要改一大堆。选型时让代理把芯片手册提前发过来重点核对 0x00~0x1F 这些基础寄存器是否和主流芯片一致。驱动支持Linux 内核 phylib 框架对绝大多数常见 PHY 都有通用驱动支持只要厂商遵循 802.3 标准基本拿来就能跑。switch 芯片则不同很多需要厂商提供 SDK 或者内核 patch。选型前先确认 SDK 的版本、维护周期、以及是否支持你当前的内核版本。5.3 国产 PHY 与 Switch 绕不开的几件事国产 PHY 芯片这两年是主流选择但有几个特质要注意。一是文档完整度差异大遇到问题去查勘误表有些原厂自己都说不清只能现场量波形验证。二是样片支持力度建议选大代理渠道能拿到 FAE 支持的项目会顺利很多。三是量产一致性同一型号批次不同MDI 走线对信号质量的影响可能不一样产线测试时链路误码率标准差如果太大要警惕。我自己的原则是关键主芯片CPU/SoC用大厂稳定型号PHY 和 switch 这类周边芯片国产和进口都备一个 pin-to-pin 方案PCB 阶段就预留兼容位置。这样即便出现不可控的供货风险也能快速切换不至于重新画板。6. 常见问题与排查技巧实录我把这些年遇到的高频问题整理成表方便你做快速对照。每一行都是真实项目里“卡壳”过的情况排查手段可以直接抄。现象可能原因排查手段解决建议link 常亮但无数据MAC/PHY 双工不一致、VLAN 配置错ethtool 查看速率双工tcpdump 抓包统一双工模式确认 CPU 口加入 VLAN只有百兆没有千兆RGMII 延迟不匹配、线缆质量问题换短网线检查 CRC 错误计数调整 phy-mode 延迟参数换正规超五类以上线缆CRC 错误随温度上升RGMII 时序裕量不足ethtool -S 看 rx_crc_errors修改 RX/TX 内部延迟组合优化 PCB 走线MDIO 读写报错PHY 地址 strap 冲突、IO 电压不匹配测量 strap 管脚电平修正 PHY 地址检查电平转换芯片自协商结果异常对端网口速率受限或本端 PHY 时钟不稳固定速率测试看 PHY CLK125固定为百兆/千兆测试排查时钟毛刺起机时 PHY 初始化失败复位时序不够dmesg 查看 phy 驱动注册时间拉长 reset-deassert-us或延后 phy_probe6.1 一个万能排查顺序救过我好几次当你面对一个“网口不通”的设备按这个顺序排错能省下大量时间先用网线把设备直连一台已知正常的电脑排除对端问题。再通过串口或 console 进系统用dmesg | grep -i phy看 PHY 驱动是否成功 probe地址是否和原理图一致。然后用ethtool eth0查当前 link、速率、双工状态。如果 link up但通过 ping 不通网关用tcpdump -i eth0看是否有 TX/RX 包。收到 RX 但不会回包问题在 MAC/VLAN/路由完全没有 RX问题在 PHY/物理层。最后用ethtool -S看rx_crc_errors、rx_missed_errors等计数判断是时延问题还是驱动丢包问题。6.2 现场实测的记录习惯调试嵌入式网络设备最怕“拍脑袋”。我的习惯是每次改一个变量就把改动和现象对应记录。比如“把 phy-mode 从 rgmii-id 改成 rgmii-txid 后1000 次大包丢包从 120 降到 2”这种记录比“好像好了”有用得多。这里有个非常实用的小命令组合一条命令做双向大包压力测试配合 ethtool 计数抓问题是项目验收阶段的保留项目。ping -s 1472 -c 1000 192.168.1.1 ethtool -S eth0丢包只要不为 0就继续查。我见过不少工程师测试时用默认小包 ping 几十个觉得没问题就收工结果一上生产环境就把问题暴露出来。大包测试、长时间压力测试、温度变化测试这三样才是真正考验链路不稳定问题的试金石别看“不是刚需”越是大规模部署越要提前测透。回到选型这件事上我个人的体会是芯片参数再漂亮都不如“好调、好换、文档全”三个词管用。嵌入式产品增量成本里networking 这一块的隐藏成本往往不在 BOM 价格表里而在调试工时、产线故障率、售后返修率上。下一期我可以专门讲讲具体型号之间的对比以及 RTL8367、Marvell 88E 系列、国产 PHY 芯片在实战里的差异表现。最后再分享一个小技巧如果你手头有一块调通的板子先把它的寄存器配置 dump 一份存成文件等新板子调不通时做一次寄存器 diff很多问题一瞬间就清楚了。这个习惯帮我省下的时间真的不是一两天能算完的。