尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

RK3566网卡DMA engine initialization failed故障排查与解决

RK3566网卡DMA engine initialization failed故障排查与解决 1. 问题背景RK3566 平台上的“DMA engine initialization failed”到底是什么1.1 报错日志现场还原很多 RK3566 板卡刷了 Android 11 之后开机阶段在串口或者 adb logcat 里会看到这么一排熟悉的日志[ 3.123456] stmmaceth 0000:01:00.0: DMA engine initialization failed [ 3.123512] stmmaceth 0000:01:00.0: stmmac_dvr_probe: DMA engine initialization failed有的 BSP 打印格式不完全一样前缀可能是eth0也可能是fe2a0000.ethernet甚至有的内核版本把stmmaceth换成了dwmac-rk。但不管前缀怎么变核心关键信息就是那一条DMA engine initialization failed。第一次遇到这个报错的人十有八九会先去检查网线、路由器、交换机。实际上这行日志跟物理网线一毛钱关系都没有。它表示网卡 MAC 控制器内部的 DMA 引擎没有完成初始化也就是说内核在 probe 网卡驱动的时候直接返回错误了。结果就是开机后ifconfig -a根本看不到 eth0或者看到 eth0 但无论怎么 up 都起不来。我把这个报错的排查过程完整梳理了一遍包括踩过的坑、花过冤枉时间的地方以及最终怎么一步步定位到根因。这篇文章适合正在调 RK3566/RK3568 平台网口、做 Android 系统定制或者嵌入式 Linux BSP 开发的工程师。初学的同学也能跟着思路走一遍搞懂 stmmac 驱动和 DMA 初始化的来龙去脉。1.2 这个错误的本质是网卡控制器没起来不是物理网线问题RK3566 这颗芯片的千兆以太网控制器在 Linux/Android 内核里通常由 Synopsys DesignWare 的stmmac驱动负责再搭配 Rockchip 的dwmac-rk平台驱动做适配。简单理解网口工作的完整链路分三层MAC 控制器负责以太网帧的封装、解析、流量控制等协议层工作也就是 GMAC。DMA 引擎负责把内存里的数据描述符和帧数据自动搬运到 GMAC或者把 GMAC 收到的数据搬回内存。PHY 芯片负责物理层信号的编解码常见型号有 RTL8211F、YT8531 等。DMA engine initialization failed这个报错发生在第一层和第二层之间也就是 MACDMA 层面还没轮到 PHY 出场。驱动在stmmac_dvr_probe阶段尝试初始化 DMA 引擎结果失败了。打个比方这就像你买了一台自动售货机机器内部的出货机械臂没有正常归位机器一直报“电机初始化失败”。这时候你站在机器前面观察商品展示灯亮不亮、投币口有没有反应根本解决不了机械臂的问题。PHY 灯亮不亮就好比展示灯亮不亮它只能说明 PHY 芯片本身通电了不能说明 MAC 侧的 DMA 已经准备就绪。2. 原理拆解为什么 RK3566 网口会卡在 DMA 引擎初始化2.1 RK3566 以太网控制器与 DMA 引擎的关系先说说stmmac驱动里的 DMA 到底是个什么角色。以太网控制器工作时CPU 不可能一个字节一个字节地去收发包那样效率太低。DMA 引擎的价值在于CPU 只需要把数据放到内存里写好描述符DMA 就会自动把数据从内存搬到 GMAC 发送或者从 GMAC 搬到内存接收。整个过程 CPU 几乎不用干预。在stmmac驱动里DMA 初始化会做这么几件事申请 DMA 描述符的内存空间。初始化 DMA 控制寄存器包括突发长度、传输方向、地址位宽。设置 DMA 中断掩码。启动 DMA 传输通道。任何一步失败函数都会返回错误码驱动就往上抛最终打印出DMA engine initialization failed。RK3566 的 GMAC 不是独立芯片而是集成在 SoC 内部所以它对外依赖很多东西时钟、电源域、IO 电压、复位信号、引脚复用。任何一个依赖不满足DMA 引擎就没法正常工作。这一点和 PC 上的独立网卡差别很大PC 网卡插上 PCIe 就能用RK3566 的网口则必须由软件把周围环境全部配好。2.2 哪些路径会触发“DMA engine initialization failed”根据我这段时间的调试经验这个报错最常见的来源有四个方向设备树DTS配置不完整或者错误。这是概率最高的原因。GMAC 节点里的phy-mode、pinctrl-0、assigned-clocks、snps,reset-gpio这些字段任何一个写错或者漏写都可能让 DMA 初始化失败。尤其是pinctrlRK3566 的 RGMII 信号线非常多GMAC0 需要一组gmac0_miim加一组gmac0_rgmii_bus。如果你只配了 MIIM 引脚忘了配置 RGMII 数据总线DMA 虽然可能在寄存器层面初始化成功但实际收发数据时乱得像一锅粥最终表现和初始化失败几乎没区别。时钟、复位、电源域没有配对。GMAC 依赖sclk_gmac0、clk_mac_ref、clk_mac_ptp这几个时钟。如果某个时钟在驱动 probe 时还没准备好或者频率配错DMA 读寄存器可能就是全 0 或者随机值。还有一种情况是 GMAC 的复位信号没有释放控制器一直处于复位状态DMA 初始化当然过不去。IO 电源域配置不对。RK3566 是一个多电源域芯片不同 IO bank 可能接 3.3V 或者 1.8V。GMAC 的 RGMII 引脚如果接到vccio5或vccio6域而设备树里io-domains的电压配置和硬件实际供电不一致引脚电平就不稳定。这种问题很隐蔽因为现象不固定有时候 DMA 初始化能过有时候过不了。硬件焊接或设计问题。比如 RGMII 信号线上的串联电阻虚焊、PHY 芯片复位电容贴错、供电电感损坏。这类问题虽然属于硬件但最终的表现往往也是DMA engine initialization failed。2.3 常见误判PHY 灯亮不代表 DMA 初始化成功我在排查这类问题的时候经常听到的一句话是“网口灯都亮了怎么还是不通”这里要强调一下PHY 灯亮只能说明 PHY 芯片这边检测到了物理链路比如网线另一端的设备已经协商出 link但它完全不等于 MAC 控制器已经正常工作。PHY 和 MAC 是两回事。PHY 负责的是物理层它甚至可以不依赖 MAC 独立完成链路协商。也就是说PHY 灯亮只能让你知道从 PHY 到对端设备这一段物理连接没问题。但从 PHY 到 SoC 内部 GMAC 之间的 RGMII 总线有没有正常通信DMA 能不能搬运数据那是另一码事。所以以后再看到DMA engine initialization failed先放下“换根网线试试”的想法直接往 MAC 控制器、DMA 引擎、设备树三个方向去查。3. 实操排查从日志到根因的四步定位法3.1 第一步确认驱动是否成功 probe拿到报错日志第一件事不是改代码而是把现场信息收集完整。用串口或者 adb 进到系统里先抓一遍内核日志adb root adb shell dmesg | grep -i stmmac dmesg | grep -i dwmac dmesg | grep -i gmac正常情况下如果驱动进入 probe 并且走了一部分流程你会看到类似[ 2.123456] stmmaceth 0000:01:00.0: Register MEM_TYPE_PAGE_POOL [ 2.123567] stmmaceth 0000:01:00.0: Setting latency timer to 64如果只有最后的DMA engine initialization failed说明前面的准备工作已经做了但 DMA 相关寄存器操作失败了。还可以查一下驱动有没有绑定到设备节点上ls -l /sys/bus/platform/drivers/stmmac/ ls -l /sys/bus/platform/drivers/dwmac-rk/如果驱动列表里没有对应的设备目录说明设备树 node 状态可能是disabled或者 compatible 字符串和驱动不匹配。这时候去读设备树cat /proc/device-tree/ethernetfe2a0000/status cat /proc/device-tree/ethernetfe2a0000/compatiblestatus如果是disabled直接改成okay重新编译。compatible如果和驱动里不匹配就要检查内核 config 或 platform driver 列表。3.2 第二步检查设备树关键节点RK3566 双网口平台通常有 GMAC0 和 GMAC1对应地址是fe2a0000和fe2c0000。排查前先看好自己板子用的是哪个控制器。一个常见的 RK3566 Android 11 GMAC0 设备树节点长这样gmac0 { status okay; phy-mode rgmii; clock_in_out input; snps,reset-gpio gpio2 RK_PB3 GPIO_ACTIVE_LOW; snps,reset-active-low; snps,reset-delays-us 0 50000 50000; pinctrl-names default; pinctrl-0 gmac0_miim gmac0_rgmii_bus; assigned-clocks cru SCLK_GMAC0, cru SCLK_GMAC0_OUT, cru CLK_GMAC0_PTP; assigned-clock-rates 125000000, 25000000, 100000000; phy-handle phy0; phy0: ethernet-phy0 { reg 0; }; };这中间几个参数是踩坑重灾区phy-mode。RK3566 外部 PHY 常见的配置是rgmii或者rgmii-id。如果 PHY 和 PCB 设计里已经做了 RX/TX delay 补偿就写rgmii-id如果 delay 由 SoC 侧配置写rgmii。这里写错轻则链路协商失败重则 DMA 初始化阶段就直接报错。到底用哪个不要拍脑袋去查原理图里 PHY 芯片的 delay 配置引脚或者 PHY 内部寄存器默认值。assigned-clock-rates。SCLK_GMAC0_OUT是输出给 PHY 的参考时钟通常 25MHz 对应 100M 模式125MHz 对应 1000M 模式。但很多 PHY 的参考时钟是固定输入比如硬件设计上就是用 25MHz 晶振给 PHY 提供时钟这时候SCLK_GMAC0_OUT就不应该配成 125MHz。这个值配错PHY 工作就不稳定MAC 侧 DMA 初始化也可能牵连失败。pinctrl-0。一定要确认gmac0_miim和gmac0_rgmii_bus两个 pin group 都在。RGMII 需要 TXD[0:3]、RXD[0:3]、TXCTL、RXCTL、TXCLK、RXCLK 一共 12 根信号加上 MDIO 和 MDC少一根都不行。除了 GMAC 节点本身还要看io-domains节点。RK3566 的 GMAC 引脚如果接在vccio5域那么io_domains { status okay; vccio5-supply vcc_1v8; };这里的电压值必须和硬件实际供电一致。我在一块板子上看到过vccio5-supply配成 3.3V但硬件上这个 bank 用的是 1.8V结果网口时好时坏非常折磨人。3.3 第三步核对时钟、复位与 IO 电源域如果设备树看起来没问题下一步就去查实际运行时的时钟状态。RK3566 的 debugfs 接口一般能拿到时钟摘要cat /sys/kernel/debug/clk/clk_summary | grep -E gmac|mac_ref|mac_ptp正常状态会看到类似sclk_gmac0 1 1 125000000 0 0 sclk_gmac0_out 1 1 25000000 0 0 clk_gmac0_ptp 1 1 100000000 0 0如果哪个时钟 enable 计数为 0或者 rate 是 0说明驱动没有成功申请。这时候回头查设备树里的assigned-clocks和assigned-clock-parents。RK3566 的 CRU 比较复杂某些时钟需要先设 parent 再设 rate顺序反了会导致设置不生效。复位引脚也是个容易忽略的点。如果 PHY 的复位脚挂在 SoC GPIO 上但 GPIO 默认状态把 PHY 拉在复位里那 MDIO 都读不到 PHY。我习惯先在 shell 里手动拉一下复位cat /sys/kernel/debug/gpio先确认 GPIO 当前状态。如果频率允许直接用示波器量 PHY 复位脚看它是不是在上电后被拉高释放了。如果一直低电平查硬件设计看看复位脚是不是被某个电容和电阻搞成默认低了。3.4 第四步PHY 通信链路验证DMA 初始化失败很多时候还会伴随 PHY 探测不到。stmmac驱动在 probe 阶段会通过 MDIO 总线去读 PHY 的 ID 寄存器如果读不到DMA 初始化也过不去。验证 PHY 是否存在可以用ls /sys/bus/mdio_bus/devices/ cat /sys/bus/mdio_bus/devices/*/phy_id以 RTL8211F 为例phy_id通常读出来是0x001cc916。如果你怎么都读不到 PHY ID重点查三个东西PHY 芯片的 MDIO 地址在硬件上是怎么配置的跟设备树里reg对不对得上。MDC/MDIO 两根线的上拉电阻有没有贴。MDIO 是开漏信号一般需要 4.7kΩ 到 10kΩ 上拉到 IO 电源没上拉绝对读不到。PHY 的复位脚有没有被拉死或者复位时序有没有问题。4. 解决方案与代码级修正4.1 设备树修正示例从报错到能正常出 eth0我最近调过一块 RK3566 双网口板卡GMAC0 一直报DMA engine initialization failed。最终定位到两个问题第一pinctrl-0漏了gmac0_rgmii_bus第二phy-handle指向的地址是 0但硬件上 PHY 的 MDIO 地址实际是 1。修正后的关键设备树片段如下gmac0 { status okay; phy-mode rgmii-id; clock_in_out input; snps,reset-gpio gpio2 RK_PB3 GPIO_ACTIVE_LOW; snps,reset-active-low; snps,reset-delays-us 0 100000 100000; pinctrl-names default; pinctrl-0 gmac0_miim gmac0_rgmii_bus; assigned-clocks cru SCLK_GMAC0, cru SCLK_GMAC0_OUT, cru CLK_GMAC0_PTP; assigned-clock-rates 125000000, 25000000, 100000000; phy-handle phy0; phy0: ethernet-phy1 { reg 1; }; };改完重新编译 boot.img 并烧录后dmesg 里就能看到[ 2.345678] stmmaceth 0000:01:00.0: Ring mode enabled [ 2.345789] stmmaceth 0000:01:00.0: Enable RX Mitigation via HW Watchdog Timer [ 2.345890] stmmaceth 0000:01:00.0: stmmac_dvr_probe: DMA engine initialization successful看到successful才能说明 DMA 这关过了。4.2 内核配置与驱动补丁设备树修正后如果还报错就要看内核配置。RK3566 Android 11 的 defconfig 里以下配置必须确认开启CONFIG_STMMAC_ETHy CONFIG_DWMAC_ROCKCHIPy CONFIG_MDIO_DEVICEy CONFIG_MDIO_BUSy CONFIG_PHY_REALTEKy CONFIG_PHY_MICRELy CONFIG_PHY_ROCKCHIP_INNO_USB3y其中CONFIG_PHY_REALTEK和CONFIG_PHY_MICREL分别对应 Realtek 和 Micrel 的 PHY 驱动具体选哪个看你板子上的 PHY 型号。YT8531 这类国产 PHY 可能需要CONFIG_PHY_MOTORCOMM或者 Rockchip 补齐的驱动具体要查内核源码里的支持列表。另外有一个我踩过的坑部分 RK3566 BSP 内核版本里stmmac的 DMA 初始化失败路径没有把已经申请的描述符内存释放干净。如果系统在休眠唤醒后重新初始化 DMA可能出现二次失败。针对这个问题要么升级到官方修复后的内核要么在驱动里手动补一下资源释放。这个补丁需要根据内核版本调整这里不贴固定代码但排查时可以重点看stmmac_main.c里的stmmac_dma_init函数和free_dma_desc_resources函数的调用关系。4.3 硬件层面需要复核的引脚与电源软件调到怀疑人生的时候不妨回头看一眼硬件。根据我的经验以下几个位置是硬件问题的高发区PHY 的供电。RTL8211F 一般需要 3.3V 的 VDDIO 和 1.05V 的核心供电。如果供电的 LDO 输出纹波太大PHY 的状态机就不稳定。有一个很典型的现场网口平时正常但 CPU 负载一高网络就闪断dmesg 里还会出现 DMA 相关的报错。这种大概率是电源问题不是软件问题。RGMII 信号线上的串联电阻。RK3566 的 RGMII 总线一般要求每根信号线串联 22Ω 或者 33Ω 电阻用来抑制信号反射。如果某个电阻漏贴或者阻值错信号边沿质量就差DMA 初始化阶段可能还能蒙混过关但跑千兆流量时丢包率非常高。PHY 的参考时钟。PHY 芯片一般需要一个 25MHz 的参考时钟可能是 SoC 输出也可能是外部晶振。这个时钟质量直接决定了 PHY 能不能正常建立链路。用示波器量一下25MHz 频率偏差不能超过 ±50ppm幅度也要在芯片手册范围内。MDIO 上拉电阻。这是很多人会忽略的。MDIO 是开漏信号必须要有上拉电阻才能被正确读取。有些开发板上没贴这个电阻软件上怎么查都查不到 PHY最后用万用表一测才发现 MDIO 线电平不对。5. 常见问题与避坑清单5.1 我踩过的三个最隐蔽的坑先说第一个改完设备树没有重新打包 dtbo.img。Android 11 的启动流程里内核和设备树可能是分开的。RK3566 平台经常用 DTBO 分区单独存放设备树。如果你只改了 dts 源文件编译了 dtb但没有重新生成 dtbo.img 并烧录那么实际跑的还是旧设备树。这个坑我踩过一次调了一整天最后发现自己一直在用旧配置。建议改设备树前先把产物链路理清out/target/product/rk3566/dtbo.img out/target/product/rk3566/boot.img有些 BSP 会把 DTB 直接嵌进 boot.img有些则放 DTBO 分区。务必确认你烧录的文件确实包含了修改后的配置。第二个坑在 Android 上层用ifconfig eth0 up失败就以为驱动没加载。Android 11 的网络架构和普通 Linux 不一样netd对网络接口有很严格的管理策略。即使 DMA 初始化成功eth0 没被系统网络管理服务正确接管之前你手动 up 也可能失败。所以我要求的判断顺序是先看dmesg再看/sys/class/net/最后才用ifconfig。如果/sys/class/net/eth0目录存在说明接口已经注册了dmesg 里显示 DMA 初始化成功说明驱动没问题剩下的可能是 Android 网络管理的事。第三个坑GMAC0 和 GMAC1 看混了。RK3566 有两个 GMAC 控制器一个地址在fe2a0000另一个在fe2c0000。如果板子原理图上用的是 GMAC1但设备树里你改的是 GMAC0那 dmesg 里照样能看到报错但根因根本不在这个节点。排查前先确认板子网口走的是哪一路别看到fe开头的地址就以为是同一个。5.2 问题排查速查表我把整个排查过程整理成一张表放在手边遇到问题直接对照现象排查方向命令/方法DMA initialization failed设备树 pinctrl/statuscat /proc/device-tree/ethernetfe2a0000/statusDMA init 失败同时 PHY 无响应PHY 复位/电源/MDIO 上拉ls /sys/bus/mdio_bus/devices/PHY 能读到 ID但 network no carrierphy-mode/时钟速率dmesg grep mdio核对assigned-clock-rates时好时坏IO 电源域/电压量 RGMII 引脚电平核对io-domains休眠唤醒后网口失效DMA 资源释放/驱动 pm bug唤醒后抓 dmesg搜stmmac千兆不通但百兆正常RGMII 信号完整性/phy-mode delay示波器量 RGMII 时钟和数据线5.3 长期稳定性建议DMA engine initialization successful只是一个开始真正让产品稳定还需要做几轮压力测试。我建议在板卡量产前至少完成以下验证反复插拔网线观察 dmesg 里有没有新的 DMA 或者 PHY 报错。执行 ping 大包压力测试ping -s 1400 -f持续跑一晚上看掉包率。测试休眠唤醒 100 次每次唤醒后确认 eth0 链路自动恢复。用ethtool -S eth0观察网卡计数器中是否有rx_error、tx_aborted这类异常增长。我遇到过一块板子DMA 初始化已经成功但跑千兆吞吐测试时tx_timeout频繁出现。最后定位到是 RGMII 时钟线走线太长信号质量不合格。这种情况下软件无论怎么调都救不回来只能改 PCB。6. 最后再分享一个小技巧调试 RK3566 网口问题时我习惯在设备树里临时把无关的功能关掉比如蓝牙、WiFi、USB 电源管理尽量让系统保持在一个简单状态。然后把内核日志等级调低保证串口能抓全所有 stmmac 相关的打印echo 8 /proc/sys/kernel/printk这样一个干净的环境里网口报错更容易复现也更容易定位。等确认 DMA 初始化稳定通过之后再逐步把其他功能打开看有没有资源冲突。另外如果你手里有示波器建议把 PHY 复位脚的时序抓出来看。我遇到过一次现象开机前 100ms PHY 处于复位状态而设备树里snps,reset-delays-us只配置了 50ms导致 DMA 初始化尝试访问 PHY 时 PHY 还没准备好。把复位延时调到 100ms 之后问题立刻消失。这类时序问题纯靠读设备树是看不出来的必须结合硬件时序来解决。
返回列表