1. 报错的现场:先搞清楚日志从哪来、意味着什么
先直接看报错日志长什么样。常见是在 Android 11 启动阶段的内核日志里,也就是 dmesg 或者串口 log,刷出这么一行:
rk_gmac-dwmac fe2a0000.ethernet: DMA engine initialization failed注意前面还有个驱动前缀,不同 SDK 版本可能略有差异。有的平台打印是:
stmmaceth: DMA engine initialization failed也有的把地址段换了,比如 fe010000.ethernet、fe2a0000.ethernet,这都正常,取决于 RK3566 上你到底用的是哪个 MAC 控制器。看到这行日志后不要慌,它只是最终结果,真正原因在这行日志之前的十几行里。
先讲日志怎么抓。正常情况下,RK3566 的 Android 11 系统开机时网口驱动就已经在跑,如果你有串口,直接在串口终端看到全部启动日志是最省事的。如果没有串口,那就进系统后用 adb shell 抓:
adb shell dmesg | grep -i "eth\|dma\|stmmac\|gmac\|rk_gmac"如果要看完整启动阶段的网络初始化日志,最好在驱动加载的时间点抓,不然等系统完全起来,dmesg 的 ring buffer 可能已经被刷掉一部分。这里有个实操小技巧:Android 系统里 dmesg 权限通常受限制,需要 root 或者至少是 userdebug 版本,否则看不到内核日志。我一般习惯在 BoardConfig.mk 里把内核 cmdline 加上 ignore_loglevel,同时把 console=ttyFIQ0,115200 保留,方便串口完整输出。
另外,Android 11 上主网口驱动(以太网)是跑在 kernel 里的,所以 logcat 里基本看不到这个报错,除非上层 EthernetService 在尝试打开网络时失败,会出现类似 Ethernet network is lost 之类的提示。核心还是看 dmesg。
拿到日志后,关键不只是最后一行,而是从“probe”开始的所有网络相关输出。我一般会这样过滤,把所有网络初始化相关的行一次列出:
dmesg | grep -iE "eth|gmac|stmmac|dma|clk|mdio|phy|reset" | head -100这样能很快定位问题发生的阶段。
2. “DMA engine initialization failed”背后的完整链路解析
要解决这个报错,咱们得先搞明白这行日志到底在说什么。
2.1 RK3566 上其实有两个 MAC 控制器,别搞混
RK3566 的 TRM 里写得很清楚,这个 SoC 集成了两个以太网 MAC:
- GMAC1,对应设备树节点通常是 gmac1,基地址一般是 fe010000.ethernet(不同 SDK 可能叫法不同)。
- GMAC0,基地址一般是 fe2a0000.ethernet,在部分开发板上被配置成 RMII 接口,也有配置成 RGMII 的。
你看到的报错地址是 fe2a0000,那就是 GMAC0。是 fe010000,就是 GMAC1。这两个控制器在软件配置上都要走 stmmac 驱动,硬件上内部集成了 DMA 引擎、MAC 核、以及 MDIO 控制器,只是对外接口和时钟源不一样。
DMA engine 这个词就是 stmmac 驱动框架里的 DMA 控制器模块。RK3566 的 GMAC 使用的是 Synopsys DesignWare MAC 的 IP,驱动是内核标准驱动 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c。这个驱动框架里,有一个函数叫 stmmac_dma_engine_init,专门负责初始化 DMA 控制器。如果这个函数里面发生任何失败,驱动就会直接打出 “DMA engine initialization failed” 然后 probe 失败。
所以可以初步判定:这行日志是在驱动 probe 流程中打印的,不是网络运行时的错误。也就是说网口驱动根本没有初始化成功,网口自然也不会出现。
2.2 stmmac 驱动的启动时序
把 stmmac 驱动的 probe 流程理清楚,排查才能有的放矢。核心过程大致是:
- 平台驱动匹配设备树节点,解析 reg、interrupt、phy-mode、clock-names 等属性。
- 获取时钟资源,通过 clk_prepare_enable 启动相关时钟。
- 获取复位信号,deassert 复位(如果有)。
- MDIO 总线注册,扫描总线上的 PHY。
- PHY 连接,协商模式配置(RGMII/RMII、速率)。
- stmmac_open 或 probe 阶段的 DMA 初始化。
stmmac 驱动的 DMA 初始化函数核心路径长这样(源码摘自内核 stmmac_main.c):
static int stmmac_dma_engine_init(struct stmmac_priv *priv) { /* 初始化 DMA 接收/发送描述符 */ ret = stmmac_init_dma_engine(priv); if (ret < 0) { dev_err(priv->device, "DMA engine initialization failed\n"); return ret; } ... }而 stmmac_init_dma_engine 内部做的事情,大体是初始化 DMA 控制器的描述符、使能 DMA 中断、配置总线模式,还有 DMA 控制器的几个关键寄存器写入。
很多人在这个阶段犯迷糊,以为 DMA engine 报错就是硬件 DMA 坏了。实际上,这个函数失败的原因非常多样,最常见的是 ** 基础资源根本没有就绪 **,比如时钟没起来、PHY 没有探测到、复位信号一直拉死,都会导致后续 DMA 初始化没有意义或者直接失败。
2.3 日志中出现 DMA 失败之前,到底还发生了什么
实战中看日志,最有价值的不是那一行最终错误,而是它前面的信息。举个例子,一份典型的失败日志如下:
[root@rockchip-rk3566:/]# dmesg | grep -iE "eth|gmac|stmmac|dma|mdio|phy" [ 1.238974] rk_gmac-dwmac fe2a0000.ethernet: no reset control found [ 1.246014] rk_gmac-dwmac fe2a0000.ethernet: IRQ eth_wake_irq not found [ 1.253666] rk_gmac-dwmac fe2a0000.ethernet: no reset control found [ 1.260997] rk_gmac-dwmac fe2a0000.ethernet: device MAC address xx:xx:xx:xx:xx:xx [ 1.270063] rk_gmac-dwmac fe2a0000.ethernet: clock input frequency is 125000000 [ 1.278140] rk_gmac-dwmac fe2a0000.ethernet: cannot get clk tx [ 1.284452] rk_gmac-dwmac fe2a0000.ethernet: cannot get clk rx [ 1.291227] rk_gmac-dwmac fe2a0000.ethernet: cannot get clk ref [ 1.298159] rk_gmac-dwmac fe2a0000.ethernet: cannot get clk phy [ 1.305841] rk_gmac-dwmac fe2a0000.ethernet: failed to get clks [ 1.313477] rk_gmac-dwmac fe2a0000.ethernet: DMA engine initialization failed这种情况下,根因一目了然 —— 时钟没配好。驱动要的 clock-names 在设备树里没给全,导致 clk_get 返回错误,最终 DMA 初始化失败。这基本是设备树问题,不是硬件问题。还有一种类似情况:
[ 1.238974] rk_gmac-dwmac fe2a0000.ethernet: clk tx not found [ 1.245032] rk_gmac-dwmac fe2a0000.ethernet: PHY ID not found at address 1 [ 1.253056] rk_gmac-dwmac fe2a0000.ethernet: stmmac_open: Cannot attach to PHY (error -19)PHY 没被找到,网口数据通路建立不起来,DMA 初始化自然也会失败或后续无法正常发包收包。这是第二大类根因:** 物理层链路问题 **。
所以,遇到 DMA 报错,第一步不是怀疑 DMA 本身,而是要顺着日志往前找,看基础资源是不是齐了。这就好比开车打不着火,你查了半天火花塞,结果发现油箱是空的。
3. 排查思路全拆解:从设备树到时钟配置一步步验证
下面这套排查思路是我自己在 RK3566 多款板卡上反复用过的,遇到类似报错基本能定位到根因。不要一上来就改内核代码,先从最简单的环节查起。
3.1 确认设备树节点与使用端口
拿到板子先确认你用的是哪个 GMAC 口。RK3566 的 evb 公版设备树一般同时有 gmac0 和 gmac1 两个节点。但市面上的核心板未必都引出了两个口,很多底板只做了一个网口。
查设备树里的以太网节点:
cat /proc/device-tree/gmac1/status cat /proc/device-tree/gmac0/status如果 status 是 "disabled",驱动不会跑,自然也没有 DMA 报错。这个报错出现的前提是 status 为 "okay"。如果两个节点都是 okay,但硬件上只接了一个口,另一个口会因为缺少 PHY 或时钟配置报各种错误,扫一眼就能分辨。
设备树里最关键的属性:
phy-mode = "rgmii"; // 或 "rmii" clock_in_out = "input"; // 或 "output" snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; // PHY 复位 snps,reset-delays-us = <0 10000 50000>; // 复位时序还要看 mdio 节点下的 PHY 描述:
mdio { compatible = "snps,dwmac-mdio"; #address-cells = <1>; #size-cells = <0>; phy: ethernet-phy@0 { reg = <0>; ... }; };如果这里 PHY 地址和硬件实际地址不匹配,后面会反复 PHY probe 失败。
先插一句我的经验:RK3566 的方案里,** 90% 的 DMA engine initialization failed 都不是 DMA 本身的问题**。要么是时钟没配好,要么是 PHY 没贴好或地址不对,要么是网口变压器到 MAC 的走线有问题导致 MDIO 读到全 F。
建议先用一个最简单的检查:看 CPU 能不能通过 MDIO 读到 PHY 的 ID。很多 SDK 的驱动在 stmmac_mdio_register 失败时会打日志:
mdio_bus: mdio@fe2a0000: mdio probe failed如果没有这行,说明 MDIO 总线本身是通的。如果连这行都没有,大概率是设备树里 mdio 子节点配置不对,或者 MAC 的 MDIO 引脚配置有问题。
3.2 时钟配置是最常见的坑,一条条对
RK3566 GMAC 的时钟体系是排查重点。和别的 SoC 相比,RK3566 的 GMAC 时钟比较麻烦,因为它的 RMII/RGMII 参考时钟源选择很灵活,既可以从 SoC 内部输出,也可以从外部 PHY 回传。
时钟是否正常,第一步看启动日志里的频率信息:
clock input frequency is 125000000如果这个频率不对,比如 RGMII 应该 125MHz,你看到了 25MHz,说明时钟树配置有问题,DMA 初始化不会成功。
然后看驱动到底拿没拿到时钟。RK3566 的公版设备树里,网口节点的时钟定义大致如下:
clocks = <&cru CLK_GMAC0>, <&cru CLK_GMAC0_PTP>; clock-names = "stmmaceth", "ptp_ref";但有些 SDK 版本把 GMAC0 的时钟拆得比较细,比如:
clocks = <&cru CLK_GMAC0>, <&cru CLK_GMAC0_PTP>; assigned-clocks = <&cru CLK_GMAC0>, <&cru CLK_GMAC0_PTP>; assigned-clock-rates = <125000000>, <125000000>;另一部分版本则要求辅助时钟,比如:
clocks = <&cru CLK_GMAC0>, <&cru SCLK_GMAC0>, <&cru PCLK_GMAC0>; clock-names = "stmmaceth", "mac_clk", "pclk";这里就是问题高发区。如果设备树里代码是从某个 3568 的 SDK 拷贝过来的,或者是从旧内核版本切过来的,clock-names 对不上,驱动在 clk_get 时就会失败,然后在代码里直接跳过时钟配置,后面就可能出 DMA 初始化失败。
这种排查看日志最直接。如果在启动日志里有:
cannot get clk tx cannot get clk rx cannot get clk ref cannot get clk phy那就是设备树 clk 配置与驱动代码不匹配。你去看内核源码 drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c 或者 RK 自己维护的 dwmac-rk.c,里面会列出它需要的 clock-names。
RK3566 的 dwmac-rk.c 中,常见时钟名包括:
- stmmaceth:MAC 主时钟。
- mac_clk:MAC 时钟。
- pclk:外设总线时钟。
- clk_mac_ref:参考时钟。
- clk_mac_speed:速率时钟。
- ptp_ref:PTP 参考时钟。
如果设备树没给全,驱动会一边打 warning 一边继续跑。有些版本的驱动对某些时钟要求是“必须”,缺失就会后续报错;有些是“可选”,缺失只打一行 warning。具体要看代码里的 devm_clk_get 返回值处理是if (IS_ERR()) return PTR_ERR()还是只打日志。
一句话总结: ** 遇到 DMA 报错,先确认设备树节点里 clocks 和 clock-names 与当前 SDK 的 dwmac-rk.c 完全一致 **。这是命中率最高的根因。
3.3 PHY 链路与复位时序核查
PHY 是 DMA 报错之外的第二个重灾区。很多 RK3566 方案使用的 PHY 是裕太微的 YT8531、瑞昱的 RTL8211F、或者国产的 IP101GRI 等,不同 PHY 对复位时序、参考时钟要求差别很大。
先说最简单也是最容易忽略的:PHY 的复位 GPIO。
在设备树里,RK 的 GMAC 驱动支持通过 snps,reset-gpio 等属性来控制 PHY 复位。但如果你的 PHY 复位引脚没有接到 SoC 的 GPIO,而是用 RC 延时电路或者由其他器件控制,那么设备树里就不应该配置 reset-gpio,否则驱动在初始化 PHY 时会先做一次复位,而这次复位如果和电源时序冲突,会导致 PHY 一直处于复位或者未就绪状态。
检查 PHY 有没有被正确识别,可以在板子上电后通过 MDIO 工具直接读。RK3566 的 Linux 内核通常打开 mdio 工具支持。如果没有工具,也可以在内核启动日志里找:
[ 1.305841] rk_gmac-dwmac fe2a0000.ethernet: PHY [stmmac-0:02] driver [YT8531] (irq=POLL)如果能看到 PHY 驱动被正确绑定,说明链路是通的。如果看到:
mdio_bus: mdio@fe2a0000: PHY ID 0xffffffff at address 2说明 MDIO 读不到 PHY 的 ID,那就是硬件问题,要么 PHY 没上电,要么复位一直有效,要么 MDIO/时钟线虚焊。这时候 DMA 初始化报错只是结果,不是原因。
还有一类情况是 PHY 地址冲突。YT8531 的地址由硬件引脚决定,一般为 0、1、2、3。如果设备树里写的是 reg = <0>,但硬件实际是 reg = <1>,驱动会在地址 0 上找不到 PHY,然后可能继续扫描别的地址,也可能直接失败。注意有些 PHY 芯片支持地址自动协商,但行为因厂家而异。
我实际调试过一次特别典型的案例:硬件上 PHY 的地址是 0,但软件里 mdio 子节点写的是 reg = <1>,结果启动日志里反复出现找不到 PHY,最终网络接口起不来。改回 reg = <0> 后问题消失。所以这个点一定要先核对。
PHY 的参考时钟方向也是一个大坑。RK3566 的 GMAC0 在某些方案里,CLK_MAC_REF 是从 SoC 输出的,也就是 clock_in_out = "output"。如果硬件上 PHY 的 XI 引脚恰好也接了 25MHz 晶振,而 SoC 又在往这个网络灌 125MHz,两边打架,PHY 工作一定不正常。反过来,如果 clock_in_out = "input",就必须保证外部 PHY 或晶振把时钟送到了 SoC 的 MAC 参考时钟引脚上,否则 MAC 的时钟源也是乱的。
在设备树里,这个属性一般叫clock_in_out。公版 evb 是这样配置的:
gmac0: ethernet@fe2a0000 { ... phy-mode = "rgmii"; clock_in_out = "output"; snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; snps,reset-active-low; snps,reset-delays-us = <0 10000 50000>; };如果你不确定自己的板子是 input 还是 output,看原理图上 PHY 的 REF_CLK 是谁提供的即可。这个方向错误导致的症状五花八门:有的直接 DMA 报错,有的能 link 上但 ping 不通,有的速率只有 100M。
3.4 电源域与复位检查
RK3566 的 GMAC 还有独立的电源域和复位控制。在设备树里,一般会有 power-domains 属性:
power-domains = <&power RK3568_PD_GMAC>;如果这里写错,或者驱动没有成功把电源域拉起来,后续 MAC 寄存器读写全是 0 或全 F,DMA 初始化自然失败。
检查方式也比较简单,启动日志里如果有:
rk_gmac-dwmac fe2a0000.ethernet: failed to get power domain那就是电源域配置有问题。注意 RK3566 和 RK3568 的 power 域宏可能定义不一致,如果你是在 3568 SDK 的基础上改 3566,这里也容易踩坑。
复位资源的检查,看日志里有没有这样一行:
no reset control found有些版本的 RK 驱动会把 MAC 控制器内部复位也作为一个 reset 资源,如果设备树没配,驱动会跳过。如果你在设备树里根本不需要 SoC 侧复位,那这行日志可以忽略。但如果硬件上 PHY 的复位脚被接到了 SoC 的某个 GPIO,而你在设备树里没配,PHY 可能一直处于复位态。这种情况查起来更隐蔽,因为日志不会直接提示。
我自己常用的排查方式:在板子起来后手动操作 GPIO,看 PHY 是否恢复。比如 PHY 复位脚接到了 GPIO3_B7(设备树里是 <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>),那可以:
echo 119 > /sys/class/gpio/export echo out > /sys/class/gpio/gpio119/direction echo 0 > /sys/class/gpio/gpio119/value sleep 0.1 echo 1 > /sys/class/gpio/gpio119/value不同 SDK 的 GPIO 编号算法不一样,我这里只是演示思路。通过手动复位 PHY 后再看 dmesg 是否有 PHY 驱动重新 probe 的日志,就能确认 PHY 本身是否还活着。
3.5 确认驱动配置项
除了设备树,内核的 defconfig 里也必须打开对应驱动。RK3566 的网口驱动是 stmmac 平台驱动,在 defconfig 里一般体现为:
CONFIG_STMMAC_ETH=y CONFIG_STMMAC_PLATFORM=y CONFIG_DWMAC_GENERIC=y CONFIG_DWMAC_ROCKCHIP=y CONFIG_PHYLIB=y CONFIG_MICREL_PHY=y // 如果用 KSZ9031 CONFIG_RTL8211F_PHY=y // 如果用 RTL8211F CONFIG_MOTORCOMM_PHY=y // 如果用裕太微 YT8531如果 CONFIG_DWMAC_ROCKCHIP 没开,驱动会退回到通用的 dwmac-generic 路径,对 RK3566 的时钟和电源域支持是不完整的,也会出现怪异的初始化失败。
检查当前内核实际开的配置:
zcat /proc/config.gz | grep -iE "STMMAC|DWMAC|PHYLIB|MOTORCOMM|RTL8211"有的 SDK 把 proc config 关掉了,那就直接在 kernel 源码目录下查 .config。
如果在设备树里配了 PHY 驱动,但内核里对应的 PHY 驱动没编进去,PHY 芯片会以通用 PHY 的形式存在,能 link 但可能丢特性。严重的情况下,PHY 的配置寄存器初始值不对,也可能导致传输异常,但一般不会直接导致 DMA 初始化失败。
4. 典型问题复现与处理案例
为了更有参照性,我把实际调试中碰到的几个和 DMA 报错强相关的场景整理一下,都是可以按图索骥的。
4.1 案例一:CLK_GMAC0 频率被设成 25MHz,RGMII 跑出 DMA 报错
某方案用 GMAC0 + RGMII,PHY 是 RTL8211F。启动日志如下:
[ 1.270063] rk_gmac-dwmac fe2a0000.ethernet: clock input frequency is 25000000 [ 1.278140] rk_gmac-dwmac fe2a0000.ethernet: cannot get clk tx [ 1.284452] rk_gmac-dwmac fe2a0000.ethernet: cannot get clk rx [ 1.291227] rk_gmac-dwmac fe2a0000.ethernet: cannot get clk ref [ 1.298159] rk_gmac-dwmac fe2a0000.ethernet: cannot get clk phy [ 1.305841] rk_gmac-dwmac fe2a0000.ethernet: DMA engine initialization failed这个日志的根因有两点:一个是时钟频率不对,另一个是 clk tx/rx/ref/phy 全拿不到。后者说明设备树里的 clocks 和 clock-names 没有匹配上驱动代码。
解决方法是先改设备树,把 assigned-clock-rates 设成正确的 125MHz,并且补全驱动需要的所有时钟项。RK3566 的 evb 设备树里 GMAC0 的时钟配置参考如下:
assigned-clocks = <&cru CLK_GMAC0>, <&cru CLK_GMAC0_PTP>; assigned-clock-rates = <125000000>, <125000000>;同时确认clock_in_out = "output"还是"input"。RTL8211F 在多数 RK3566 底板上是 SoC output 模式,也就是由 SoC 提供 125MHz 参考时钟给 PHY。
修改后重新编译内核,烧录后日志变成:
[ 1.270063] rk_gmac-dwmac fe2a0000.ethernet: clock input frequency is 125000000 [ 1.278140] rk_gmac-dwmac fe2a0000.ethernet: PHY [stmmac-0:00] driver [RTL8211F] (irq=POLL)DMA 报错消失,网口正常起来。这个案例希望能说明一件事: ** 不要只盯着最后一行报错,要看完整日志链 **。
4.2 案例二:PHY 芯片 YT8531 的 25MHz 晶振没贴,导致 DMA 初始化失败
还有一个很常见的硬件现象:PHY 是 YT8531,原理图上要求外部 25MHz 晶振,但贴片漏贴或贴错。此时 PHY 完全不上工,MDIO 也读不到,驱动在探测 PHY 时失败,最终 DMA 初始化失败。
这个案例的日志中,MAC 的时钟频率可能是对的(125MHz),但 PHY 没就绪。在 dmesg 里你会发现:
mdio_bus: mdio@fe2a0000: MDIO device at address 0 is missing或者:
rk_gmac-dwmac fe2a0000.ethernet: Cannot attach to PHY (error -19)这种只能硬件排查:用示波器量 PHY 的 XI/XO 引脚有没有 25MHz 波形,量 PHY 电源是否正常,量复位脚电平。软件上能做的就是把设备树里的 PHY 地址挨个试一遍,但归根到底要排除硬件问题。我自己在这个坑上浪费过两天时间,后来发现是核心板厂给错了物料封装。
4.3 案例三:RK3568 的 SDK 改的 RK3566,power-domains 索引越界
有客户拿 RK3568 的 SDK 改 RK3566 方案,设备树里 gmac 节点的 power-domains 直接复制了 RK3568 的写法和索引。RK3566 的 PD_GMAC 索引在 pmu 的 power-controller 里的编号和 RK3568 不一样,导致 pm_genpd_init 失败。
日志表现:
rk_gmac-dwmac fe010000.ethernet: failed to get power domain rk_gmac-dwmac fe010000.ethernet: DMA engine initialization failed原因是 stmmac_platform.c 在 probe 里调用 dev_pm_domain_attach 失败后会返回错误,DMA 初始化根本没走到还是走到了但寄存器读写异常。
解决方法是把 power-domains 属性对照 RK3566 TRM 修正。如果你的设备树里根本没有 power-domains 属性,驱动也能跑,但有些低功耗状态下 MAC 可能不会正确唤醒。所以这个属性建议保留且必须正确。
4.4 案例四:双网口模式,两个 GMAC 同时开启导致引脚冲突
RK3566 支持双网口,但两个 GMAC 的一些引脚会复用同一条 IO 或者同一条时钟线。如果两个节点都配了 okay,但底板实际上只接了一个 PHY,另一个 MAC 的 MDIO 地址会冲突或时钟冲突。
表现是:一个网口正常起来,另一个网口报 DMA 初始化失败。比如 GMAC0 正常,GMAC1 报错。
查设备树里 GMAC1 的 pinctrl,看引脚是否和 GMAC0 或其它外设冲突:
cat /proc/device-tree/gmac1/pinctrl-0然后对照 TRM 的 GPIO 复用表。这类问题往往是硬件工程师只设计了一个网口,但软件人员直接从公版设备树开了两个 GMAC,第二个节点自然失败。
如果确实只需要一个网口,就把未使用的 GMAC 节点 status 改为 disabled,干净利落。
5. 排查这个报错需要具备的工具与资料意识
最后聊几句平时调试这个报错时,我手边会准备的资料和工具,不一定全是软件层面的,但对快速定位很有帮助。
第一个是 RK3566/RK3568 的 TRM(Technical Reference Manual)。查 DMA 控制器寄存器、GMAC 时钟树、复位寄存器,都需要它。特别是 RGMII 的时钟树那几页,建议直接打印出来放桌上。
第二个是芯片原厂(Rockchip)的 SDK 设备树 diff。如果你手上有公版 evb 的设备树,先和你的底板设备树做 diff,重点看 gmac 节点、相关的 io-domain、pmu 节点。很多时候问题就是改设备树时抄漏了一行。
第三个是 PHY 芯片的 datasheet。RTL8211F、YT8531、IP101GRI 的 datasheet 里都有寄存器映射和地址配置说明,调试 MDIO 时会用到。比如 YT8531 的 PHY 地址默认由 AD0/AD1/AD2 引脚决定,和 RTL8211F 的地址译码逻辑还不完全一样。
第四个是一个 USB 转网口的调试工具或者一个能上网的路由器。网口起来后,先用 static IP 直连电脑测 ping,不要一上来就插公司网络,不然你分不清是 DHCP 问题还是网口问题。我自己习惯在板子上配静态 IP:
ifconfig eth0 192.168.1.88 netmask 255.255.255.0 up ping -I eth0 192.168.1.1如果 MAC 起来但是 ping 不通,可以用 ethtool 查 link 状态和速率:
ethtool eth0如果 link 是 no,说明 PHY 协商本身有问题,走 MDIO 排查;如果 link 是 yes 但 ping 不通,重点查 RX/TX 的引脚配置、时钟方向、以及设备树里 phy-mode。
6. 最后的经验谈
我自己调试 RK3566 网口问题的过程中,最深的体会是:这个报错把太多人误导到 DMA 寄存器方向去了。实际上,SoC 的 DMA 引擎本身很少出问题,绝大多数是它依赖的时钟、PHY、复位、电源没就绪。所以当你看到 “DMA engine initialization failed”,第一反应应该是:前面哪个基础资源缺失了,而不是去看 DMA 控制器寄存器。
按我现在的习惯,拿到这个日志后先做三件事:第一,看整段 dmesg 里有没有 cannot get clk 或 failed to get 字样;第二,确认 PHY 是否被 MDIO 扫描到;第三,核对设备树里 clocks、power-domains、snps reset-gpio 和 phy-mode。做完这三步,九成以上的问题都能定位出来。
如果这三步都查不出问题,再回头检查硬件:用示波器量 PHY 的 XI 时钟波形、复位引脚电平、MDIO/MDC 信号。在很多合作厂商的项目里,最后查出来是 PHY 芯片贴错或者 PCB 走线反了也不算罕见。
另外再提一个调试效率问题:很多工程师喜欢在驱动里加 printk,一行一行打日志看走到哪。这个方法不是不行,但效率偏低。更好的方式是把设备树调好之后,先用 dmesg + ethtool 验证硬件链路,再决定要不要动内核代码。因为 stmmac 框架本身已经很成熟,RK 的 dwmac-rk.c 也相对固定,真正需要你改内核驱动的场景很少,大部分都是在设备树层面就能搞定。
调试网络的另一个小技巧是打开 phy 的调试模式。有些 PHY 驱动支持查看内部寄存器,比如:
cat /sys/kernel/debug/mdio/0/regs或者使用 mdio-tools 直接读写 PHY 寄存器。通过读取 PHY ID 寄存器(寄存器 2 和 3)可以快速判断 PHY 是否响应。如果读出来是 0xffff,那说明 MDIO 链路有问题;如果读出来是 0x1cc1 之类,至少能确认 PHY 活着。
还有一点值得提醒:替换 PHY 型号时,不要只改设备树里的 compatible 或者 PHY 驱动,还要留意 PHY 芯片的电源引脚是否兼容。RTL8211F 和 YT8531 的引脚定义并不完全一样,有的板子直接替换后,PHY 的 LED、中断引脚和复位极性可能对不上,软件怎么调都没用。
总结下来,这份报错日志本身只是一个报警器。真正的工作是顺着报警器找到真正失火的房间。RK3566 平台上的网口驱动链路实际上很成熟,只要抓住设备树、时钟、PHY、电源域这几个核心点,按顺序排查,基本上都能在半天内解决。希望这篇文章能把排查顺序和验证方法讲清楚,帮你少走一些弯路。