RK3588以太网调试实战:从设备树配置到吞吐量优化

发布时间:2026/10/11 2:47:50
RK3588以太网调试实战:从设备树配置到吞吐量优化
接手这块带 RK3588 的板子时任务很明确把 Ethernet 调通。说“明确”是因为功能需求就一句话但真正做起来从硬件基线确认、设备树配置、PHY 探测到吞吐量验证每一步都可能有坑。这篇文章是 BSP 调试系列的第三篇聚焦 RK3588 平台上的 Ethernet 调试重点不是贴一份“能用”的配置就完事而是把链路拆开讲讲我实际排查时遇到的问题、定位思路和最终落地的方案。如果你也正在调 RK3588 或者类似 ARM64 平台的 GMAC这篇文章应该能帮你少走不少弯路。RK3588 的 Ethernet 控制器是 DesignWare 的 GMAC带 DMA 引擎支持 RGMII/RMII 接口内部集成了多个 DMA 通道。硬件上通常会外挂一颗 PHY 芯片通过 MDIO 总线管理。调试的难点通常不在控制器本身——大部分时候是设备树配置、PHY 复位时序、时钟方向这些细节出问题。下面我从拿到板子后的第一步开始讲。1. 拿到板子先摸底硬件基线、最小系统与驱动确认1.1 别急着改代码先确认板子上的 PHY 型号和连接方式很多人在调试 Ethernet 时上来就翻设备树、改驱动结果改了半天发现 link 还是起不来。我习惯先把原理图翻出来确认几件事用的是哪个 GMAC 控制器RK3588 有 gmac0 和 gmac1 两组PHY 接在哪个 MDIO 地址上PHY 的复位 GPIO 是哪个RGMII 接口的时钟是由 SoC 输出还是由外部晶振提供。这些信息直接决定设备树怎么写。比如某块板子上用的是 RTL8211FMDIO 地址是 0x0复位脚接在 GPIO1_B2 上那设备树里 phy 节点的 reg 属性就必须写成 0x0reset-gpios 也要指向对应的 GPIO。如果地址写错驱动在 MDIO 总线上扫描不到 PHY后面所有调试都无从谈起。确认硬件连接之后再确认 RK3588 的 SDK 里是否已经包含了对应 PHY 的驱动。大部分主流 PHYRTL8211F、YT8531、AR8033 等在内核里的 PHY 驱动都是现成的不需要额外移植。关键是要在内核配置里打开对应的驱动选项如 CONFIG_PHY_REALTEK、CONFIG_MOTORCOMM_PHY 等否则即使设备树写得再对PHY 也无法被正确识别。1.2 最小系统验证先用默认配置把接口拉起来硬件基线确认后建议先用 SDK 自带的默认配置做一次最小系统验证不要一上来就按自己的板子改。RK3588 的 SDK 里一般都会有参考板的设备树先编译一个默认内核确认 GMAC 驱动能正常加载PHY 能被扫描到再逐步改成自己板子的配置。我举个例子。默认配置启动后如果 dmesg 里能看到类似[ 2.345678] rk_gmac-dwmac fe1c0000.ethernet: no reset control found [ 2.351234] rk_gmac-dwmac fe1c0000.ethernet: IRQ eth_wake_irq not found [ 2.357890] rk_gmac-dwmac fe1c0000.ethernet: IRQ eth_lpi not found [ 2.364567] rk_gmac-dwmac fe1c0000.ethernet: PHY ID 001cc816 at 0 IRQ POLL (stmmac phy)说明 GMAC 控制器和 PHY 的 MDIO 通信已经正常PHY ID 001cc816 也能读到。这一步过了后面基本就是配置细节的问题。如果连 PHY ID 都读不到那就要先从硬件连接和 MDIO 时序查起。我见过一个情况某块板子的 PHY 复位脚和另一个外设的 GPIO 复用了系统启动时其他驱动先把 PHY 拉在复位状态导致 GMAC 驱动 probe 的时候怎么都读不到 PHY ID。这种问题在代码层面看不出来只能靠原理图排查。2. RK3588 Ethernet 链路拆解从 GMAC 控制器到设备树的关键配置2.1 数据通路上的每个环节都要心里有数RK3588 的 Ethernet 链路可以拆成四层GMAC 控制器包括 DMA 引擎、MAC 与 PHY 之间的接口RGMII/RMII、PHY 芯片本身、以及 MDIO 管理通道。调试的时候每一层都有对应的观测手段。GMAC 控制器对应的设备树节点是 gmac0 或 gmac1。这里要注意RK3588 的 gmac0 和 gmac1 在硬件上支持的模式不完全一样gmac0 支持 RGMII 和 RMIIgmac1 同样支持两种模式但具体的引脚复用、时钟源和电源域不同设备树里的 assigned-clocks、assigned-clock-rates 也要跟着调整。RGMII 接口上TX 和 RX 各有 4 根数据线加上 TX_CLK、RX_CLK、TX_CTL、RX_CTL总共 12 根信号线。在 RGMII 模式下时钟频率是 125MHz千兆或 25MHz百兆数据在时钟的上下沿都采样所以对时序要求比较高。如果 PCB 上走线长度不匹配很容易出现间歇性的丢包或者 link 不稳定的问题。MDIO 管理通道是 MAC 访问 PHY 寄存器的桥梁频率一般工作在 2.5MHz 左右。设备树里 mdio 节点的 compatible 一般写成“snps,dwmac-mdio”子节点就是具体的 PHY。PHY 的地址由硬件上的 strap 引脚决定默认是 0x0 到 0x1f 之间。2.2 设备树里最容易踩坑的几个字段以 RK3588 的 gmac1 为例实际项目中常见的一段设备树配置如下gmac1 { status okay; phy-mode rgmii; clock_in_out input; assigned-clocks cru CLK_GMAC1, cru CLK_GMAC1_PTP_REF; assigned-clock-parents cru CLK_GMAC1_RMII; assigned-clock-rates 0, 25000000; pinctrl-names default; pinctrl-0 gmac1_miim gmac1_rgmii_clk gmac1_rgmii_bus; phy-handle phy0; phy-supply vcc_phy0; mdio { compatible snps,dwmac-mdio; #address-cells 1; #size-cells 0; phy0: ethernet-phy0 { reg 0x0; reset-gpios gpio1 RK_PB2 GPIO_ACTIVE_LOW; reset-delay-us 10000; }; }; };这里有几个字段需要特别说明。clock_in_out input表示 RGMII 的 TX_CLK 由外部 PHY 提供而不是由 SoC 输出。对于 RGMII 接口如果 PHY 端有独立的 25MHz 或 125MHz 时钟源通常都设置成 input。如果设置成 outputSoC 会输出时钟给 PHY要求 PHY 工作在从模式两者必须匹配否则 link 起来后很容易出现大量 CRC 错误。assigned-clocks和assigned-clock-rates用来配置 GMAC 的时钟。RK3588 的内部 CRUClock and Reset Unit会给 GMAC 提供多个时钟源比如 RMII 时钟、PTP 参考时钟等。这里配置的 25000000 对应 25MHz是 RGMII 百兆模式下的 PHY 参考时钟频率。千兆模式下PHY 会自己产生 125MHz 时钟不需要 SoC 额外提供。phy-handle指向 mdio 子节点里的 PHY 节点。这个 phandle 必须和 mdio 子节点里定义的标签一致不然驱动找不到 PHYprobe 就会失败。reset-gpios和reset-delay-us控制 PHY 的复位时序。reset-delay-us 表示复位信号释放后要等待多久再开始访问 PHY。RTL8211F 一般建议至少 10ms如果延时太短PHY 内部还没完成上电初始化MDIO 读到的寄存器可能就是全 F。我强烈建议调试时把reset-delay-us先设大一点比如 20ms等链路稳定后再慢慢调小看最小值能到多少。这个值设置不合理会表现为“冷启动偶尔 link 不起来热重启正常”特别难排查。2.3 电源和时钟两个容易被忽略的隐性依赖设备树里phy-supply指向 PHY 的电源节点。这个不是必须的如果 PHY 的供电一直处于开启状态可以不配。但如果你发现 PHY 上电时序有问题比如 SoC 的 GMAC 控制器先 probe 完成、PHY 后上电导致 MDIO 扫描时 PHY 还没准备好那就需要靠 phy-supply 和 regulator 框架来控制上电时序。时钟方面RK3588 的 GMAC 涉及三个时钟概念MAC 时钟、PTP 参考时钟和 PHY 参考时钟。其中 MAC 时钟用于 DMA 引擎和 MAC 核心逻辑PTP 参考时钟用于时间戳功能PHY 参考时钟则通过 RGMII 接口的 TX_CLK 线传递。很多人只关注 PHY 参考时钟忽略 PTP 参考时钟结果时间戳功能异常。虽然不影响常规网络通信但如果项目里有 TSN 或者精确时间同步需求PTP 时钟就必须配好。我曾经踩过一个坑某个项目里需要用到 1588 时间戳设备树里assigned-clock-rates把 PTP 参考时钟配成了 25000000但实际 PTP 逻辑需要 125MHz 才能正常工作。结果时间戳始终不准最后对照 TRM 才查到原因。所以设备树里的每一路时钟配置最好都对照芯片手册确认一下不要照抄参考设计。3. link 起不来的典型现场从 dmesg 到 MDIO 一步步定位3.1 第一阶段确认驱动 probe 是否成功如果你改了设备树之后启动时ifconfig -a看不到 eth0或者 eth1第一步要看 dmesg 里 GMAC 驱动的输出。常见的几种情况# 情况一控制器 probe 失败通常是设备树节点 status 不是 okay或者地址写错 [ 2.123456] rk_gmac-dwmac fe1c0000.ethernet: Unsupported GMAC table [ 2.130000] rk_gmac-dwmac fe1c0000.ethernet: probe failed # 情况二PHY 扫描不到通常 MDIO 通信异常 [ 2.345678] rk_gmac-dwmac fe1c0000.ethernet: no PHY found看到no PHY found的时候先不要急着怀疑驱动。用示波器或者万用表量一下 MDIO 和 MDC 引脚上的波形确认 SoC 有没有在扫描 PHY。如果 MDC 上有时钟输出MDIO 上有数据翻转但 PHY 就是没响应那大概率是 PHY 地址不对或者复位脚一直被拉低。3.2 第二阶段绕开设备树直接操作 MDIO 总线SDK 的内核里一般会开启 PHY 直读功能可以绕过网络协议栈直接通过 MDIO 总线读写 PHY 寄存器。比如 mdio-tools 这个工具包里的mdio命令可以手动扫描 PHY 地址# 扫描 0-31 号地址上的 PHY mdio scan eth0正常的情况下某个地址上会打印出 PHY ID。比如mdio scan eth0 Scanning eth0 MDIO bus... 0: PHY ID 001cc816, addr 0如果扫描不到可以用逻辑分析仪抓 MDIO 波形看 SoC 发出的地址和 PHY 的 strap 引脚配置是否一致。这里有个经验很多板子的 PHY 地址是由电阻上下拉决定的硬件同事改版时容易把 strap 电阻漏焊或者贴错导致地址和原理图对不上。3.3 第三阶段复位时序和 GPIO 的确认确认 PHY 能被 MDIO 访问到之后下一步就是检查复位时序是否满足要求。设备树里配置了reset-gpios、reset-delay-us之后驱动在 probe 时会拉低复位脚然后延时再释放。用示波器量复位脚可以看到一个低电平脉冲脉冲宽度就是reset-delay-us设置的值。如果这里设置的时间太短PHY 内部的上电初始化还没完成GMAC 驱动去读 PHY ID 时PHY 可能还在复位状态或者寄存器值不稳定。表现出来的现象就是 dmesg 里 PHY ID 时有时无或者读出来一个奇怪的值比如 0x00000000。把延时加大到 50ms 再试如果稳定了再慢慢往下调。我在另外一块板子上遇到过 PHY 的复位脚被 GPIO 子系统里的其他驱动抢先占用导致 GMAC 驱动 probe 时请求 GPIO 失败。dmesg 里报gpio: pin ... cannot be requested这种情况要检查设备树里的 pinctrl 配置是否有冲突。3.4 第四阶段link 起来了但起不彻底——自协商问题有时候ifconfig eth0 up之后ethtool eth0能看到 link detected但协商速率不对比如千兆口协商成了百兆。这种问题大多出在 PHY 的 strap 配置或者 RGMII 时钟上。先用 ethtool 看当前协商结果ethtool eth0 Settings for eth0: Supported ports: [ TP MII ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Speed: 100Mb/s Duplex: Full Auto-negotiation: on如果 peer 端明明是千兆口但协商结果停在百兆大概率是 PHY 的千兆能力没有被识别。可以用 ethtool 强制千兆模式测试ethtool -s eth0 speed 1000 duplex full autoneg off如果强制千兆后 link 能起来说明 PHY 硬件本身支持千兆问题在自协商过程。常见原因是 PHY 的 strap 引脚把千兆能力禁掉了或者晶振频率不对比如应该 25MHz 实际用了 50MHz。也有可能是 RGMII 的 RX_CLK 时序问题导致协商阶段的 link 脉冲没有被正确解析。4. PHY 寄存器直读直写深入到 clause 22/45 的调试手段4.1 理解 PHY 寄存器的基本布局现代 PHY 芯片内部有两种寄存器空间clause 22 是经典的 32 个 16 位寄存器clause 45 是扩展寄存器空间分为 device ID 和 register 地址两级。大部分千兆 PHY 同时支持两种访问方式但扩展功能比如 LED 控制、EEE、固件版本都放在 clause 45 空间里。常用的 clause 22 寄存器包括寄存器地址名称功能0x0BMCR控制复位、自协商、速率设置0x1BMSR状态link 状态、协商完成、能力0x2PHY ID HighPHY 型号高 16 位0x3PHY ID LowPHY 型号低 16 位0x4ANAR自协商能力通告0x5ANLPAR对端能力通告0x6ANER自协商扩展状态通过mdio命令可以直接读写这些寄存器。比如读取 PHY IDmdio read eth0 0x2如果读到 0x001c再读 0x3 看到 0xc816就可以确认这颗是 RTL8211F实际 ID 因芯片版本可能略有不同。4.2 用 BMSR 判断 link 状态和协商结果BMSR地址 0x1里 bit 2 是 link 状态位link 正常时读出来应该是 1。但这只是“当前瞬间”的状态很多时候需要连续读几次看是不是稳定。更关键的是 ANLPAR地址 0x5它记录了这次协商过程中对端通告的能力。举个例子如果对端是千兆交换机ANLPAR 里应该能看到 1000baseT 的位被置上。如果读出来只有 100baseT说明 PHY 的对端通信过程在千兆能力上出了问题要么是线缆问题比如只接了 4 芯线要么是 RGMII 时钟导致协商阶段千兆探测失败。我在某个项目里遇到的场景是用短的成品网线测试没问题换成长网线约 30 米就协商成百兆了。用 mdio 读 ANLPAR发现对端千兆能力位确实被置上了但 BMSR 的 link 状态不稳定——最终定位到 PCB 上 RGMII 差分对走线过长并且没有做等长处理导致千兆模式下信号质量不达标。这种问题用软件手段很难绕过去只能改板。4.3 通过寄存器定位 CRC 错误和丢包网络通信中出现间歇性丢包时可以用ethtool -S eth0看 MAC 层面的统计计数器。重点关注 rx_crc_errors、rx_fifo_errors、rx_missed_errors 这几项。比如rx_crc_errors持续增长说明接收方向的数据在传输过程中被干扰或者时钟采样位置不对。RGMII 模式下如果 RX_CLK 和数据线的相对延时不对就会导致错采数据。有些 SoC 支持在 MAC 侧配置 TX/RX 延时RK3588 的设备树里对应的是tx_delay和rx_delay参数单位是 ns需要根据 PCB 走线长度来调整。SHOW一下我在设备树里调延时的经验gmac1 { tx_delay 0x2a; rx_delay 0x1f; };这两个值每个平台默认不一样RK3588 参考设计里一般都有推荐值。如果 CRC 错误多可以尝试把 rx_delay 加 0x5 再看效果。注意这个修改要配合 PCB 走线长度来理解如果走线特别短比如 PHY 就在 SoC 旁边延时太大反而会引入问题。5. 吞吐量上不去的瓶颈中断合并、队列映射与实测数据5.1 先看 CPU 占用和中断分布link 正常、ping 通但 iperf3 测速不过 300Mbps这种情况在 ARM 平台上很常见。第一步看中断分布cat /proc/interrupts | grep eth正常情况应该是多个 IRQ 对应到多个 CPU 核心上。如果所有中断都堆在 CPU0 上DMA 中断处理就成了瓶颈。RK3588 的 GMAC 支持多队列配合中断亲和性设置可以把不同队列的中断分散到不同 CPU 上。查看当前队列数ethtool -l eth0 Channel parameters for eth0: Pre-set maximums: RX: 4 TX: 4 Current hardware settings: RX: 4 TX: 4如果 Current 值是 1就用下面的命令扩大队列数ethtool -L eth0 rx 4 tx 4注意这需要内核配置了 CONFIG_STMMAC_RING 或者对应的多队列支持。改完之后再用cat /proc/interrupts确认中断是否均匀分布。5.2 中断合并降低 CPU 开销的代价是延迟ARM 平台跑千兆时如果每个包都产生一次中断CPU 开销会非常高。开启中断合并coalesce可以把多个包的中断合并成一次处理显著降低 CPU 占用代价是增加少量延迟。查看当前中断合并参数ethtool -c eth0 Coalesce parameters for eth0: rx-usecs: 0 tx-usecs: 0默认 0 表示不合并每个包都触发中断。我通常在项目里设置成ethtool -C eth0 rx-usecs 30 tx-usecs 30这个值表示收到包后最多等 30 微秒再产生中断。如果来的包足够多中断次数会大幅减少。实测下来在某个 RK3588 平台上rx-usecs 30配合rx-frames 16TCP 吞吐能从 500Mbps 提升到接近 940MbpsCPU 占用从 80% 降到 50% 左右。但这件事情要分场景如果项目对网络延迟很敏感比如工业实时控制就不要开太激进的中断合并。30 微秒的合并延迟在大多数 Web 服务场景里可以接受但在高频交易或者实时控制场景里就是灾难。5.3 实测数据从默认配置到调优后的对比我用实际项目里的数据举个例子。平台是 RK3588 RTL8211F内核版本基于 SDK 自带的内核测试工具 iperf3测试方向是从板子到 PC 的单向 TCP 发送。默认配置队列数 1、无中断合并下测试项结果TCP 吞吐512 MbpsCPU 占用78%单核延迟ping 平均0.45 ms调优配置队列数 4、中断合并 rx-usecs 30、tx-usecs 30下测试项结果TCP 吞吐941 MbpsCPU 占用52%单核延迟ping 平均0.52 ms可以看到吞吐提升非常明显CPU 占用也降下来了。如果项目对延迟不敏感强烈建议开启中断合并。5.4 一个隐藏问题DMA 内存映射与 cache 一致性RK3588 的 GMAC DMA 使用内存描述符来管理数据包驱动默认使用一致性的 DMA 映射。如果调试时发现性能很低且伴随大量rx_fifo_errors可以检查 DMA 的描述符数量。设备树里可以配置snps,pbl和snps,txpbl来调整 DMA 突发长度。参考设计里一般有默认值如果表现不佳可以尝试加大 PBLProgrammable Burst Length。还有一个隐蔽的点如果网络吞吐忽高忽低和 CPU 频率联动说明 DMA 引擎内存带宽受到 CPU 调频的影响。可以在调试阶段把 CPU 定频在高性能档位cpupower frequency-set -g performance如果定频后吞吐明显改善说明是内存带宽分配问题。此时可以查一下系统里是否有其他外设比如 USB3、PCIe在抢占 DDR 带宽而不是急着改网络驱动。6. 一些硬件细节改进 EMC、阻抗匹配与 PCB 布局相关6.1 Ethernet 的辐射和抗干扰问题如果你的产品需要过认证Ethernet 接口的 EMC 设计就要提前注意。RJ45 座子最好选带隔离变压器的PHY 和变压器之间的走线要尽量短差分对之间保持等长。RGMII 信号属于高速数字信号如果 PCB 布局不合理除了影响信号完整性还可能成为辐射源。常见的设计参考RGMII 差分对走线阻抗控制在 100 欧姆 ±10%差分对内等长误差不超过 5mil对间等长误差不超过 20mil。PHY 芯片的电源引脚旁边要放 0.1uF 和 10uF 的去耦电容电源层要保证完整的参考平面。这些硬件细节看起来和 BSP 调试无关但如果你在软件层调了很久、CRC 错误仍然存在回头检查硬件往往是突破口。我有一次遇到的奇葩问题就是板子在低温-20 度环境下网络间歇性不通软件怎么查都查不出来最后硬件同事用示波器抓 MDIO 波形发现低温下 PHY 的复位释放时间变长了导致驱动在复位延时结束后去访问 PHY 时PHY 还没有完成初始化。最后把reset-delay-us从 10ms 改成 50ms 解决。6.2 交流耦合电容和变压器中心抽头RGMII 接口上 PHY 和 RJ45 之间的差分信号通常是交流耦合的耦合电容一般放在靠近连接器侧。这里要注意电容的容值选择常见的 0.1uF 在千兆模式下是可用的但如果选得太大比如 1uF会影响低频信号传输导致 link 建立时间变长。变压器中心抽头有的接电源有的接地取决于 PHY 或者变压器本身的规格。如果接错可能表现为能协商成功但数据传输速率上不去或者长时间运行后 link 自动掉线。调试时如果发现这些问题可以先用万用表确认电压再对照 PHY 数据手册检查。6.3 线缆和连接器的耐久性问题最后提一个容易被忽略的如果你的产品用的是非标准连接器比如自定义的防水接头线缆的长度和绞合方式都会影响千兆通信。标准的 Cat5e/Cat6 网线内部是 4 对双绞线千兆需要 4 对全部工作。如果用了只接 2 对的线缆或者连接器那只能协商到百兆。调试时先确认自己的测试环境用的是标准网线再用ethtool eth0看协商结果。如果 SiP 封装、连接器选型有问题软件上是无论如何也调不出千兆的。7. 最后再分享几个排查技巧这次 RK3588 Ethernet 调试下来我自己总结了一套排查顺序供参考先看硬件基线PHY 型号、地址、复位脚再看设备树配置phy-mode、时钟方向、复位延时然后登录系统看 dmesg 和 MDIO 扫描结果接着用 ethtool 验证协商模式和统计计数最后用 iperf3 压测吞吐。每一步之间都有明确的判断依据不要跳步。调试中我常用的几个快捷命令也一并列出来# 查看 eth 设备的驱动信息和能力 ethtool eth0 # 查看 MAC 层统计计数 ethtool -S eth0 # 查看当前队列数 ethtool -l eth0 # 查看中断合并参数 ethtool -c eth0 # 强制设置速率和双工模式 ethtool -s eth0 speed 1000 duplex full autoneg off # 查看 PHY 寄存器clause 22 mdio read eth0 0x1 # 查看 PHY 自协商对端能力 mdio read eth0 0x5如果mdio命令在 SDK 里没有可以在内核里打开 PHY 调试支持或者用 devmem2 直接操作 MDIO 控制器地址不过那样效率会低一些。RK3588 的 GMAC 整体来说不算难调主要坑集中在设备树配置和 PHY 时序上。把这两块摸透其他问题基本都能顺着 dmesg 和寄存器信息找到方向。如果你也在调这块遇到什么奇怪的现场欢迎在评论区交流我这边积累了不少案例可以分享。