尧图精选

U-Boot网络子系统深度解析:net/mac/phy三层架构与MDIO调试实战

🕒 发布时间:2026/10/2 19:17:57 📁 来源:尧图网络
1. U-Boot 网络子系统整体架构拆解1.1 为什么网络功能在 U-Boot 阶段如此关键很多人第一次接触 U-Boot 网络是在板子刚上电、系统还没跑起来的时候需要从服务器拉一个内核镜像或者根文件系统。这时候没有操作系统、没有协议栈、没有中断线程调度所有网络收发都得靠 U-Boot 自己那套精简到极致的驱动模型来完成。我见过不少工程师在调试阶段卡在这里串口能打印存储能读写但一到tftp或ping就完全没反应最后发现是 MAC 和 PHY 之间的 MDIO 通信根本没建立起来。U-Boot 的网络子系统本质上是一个“够用就好”的实现。它不追求 Linux 内核那种完整的 socket 抽象和协议分层而是把net核心层、mac控制器驱动、phy芯片驱动这三块拼在一起用最少的代码完成收发包。理解这个结构比死记某个寄存器的值重要得多。1.2 net、mac、phy 三层各自负责什么先把这个三层模型说清楚后面所有调试都围绕它展开。net 层是协议和命令的入口。你在 U-Boot 命令行敲的ping、tftp、dhcp、nfs全部由net/net.c这个文件里的逻辑来调度。它负责组装以太网帧、解析 ARP、维护 IP 地址和网关信息然后把待发送的帧交给下层驱动。net 层不关心你用的是哪个厂家的 MAC也不关心 PHY 是千兆还是百兆它只认一个struct eth_device结构体。mac 层是以太网控制器的驱动。不同 SoC 的 MAC 寄存器布局完全不同比如瑞芯微、全志、恩智浦、意法半导体各有各的初始化流程。这一层的核心任务是配置 MAC 工作模式、设置本地 MAC 地址、管理发送和接收描述符环、处理 DMA 搬运。它向上注册eth_device向下通过 MDIO 总线访问 PHY 寄存器。phy 层是那颗独立的小芯片负责把数字信号变成差分模拟信号发到网线上。MAC 通过 MDIO 接口读写 PHY 的寄存器完成自协商、速率双工配置、链路状态检测。PHY 驱动在 U-Boot 里通常由drivers/net/phy/目录下的通用框架管理配合设备树里的 PHY 地址和兼容字符串来匹配。这三层的关系可以用一个生活化的类比net 层是快递公司的调度中心mac 层是分拣流水线phy 层是最后把包裹送上货车的装卸工。调度中心决定发什么货流水线负责打包贴单装卸工负责实际搬上车。任何一环断了货都发不出去。1.3 设备树与驱动模型的绑定关系现代 U-Boot 已经全面转向驱动模型Driver Model简称 DM。网络设备的注册不再像老版本那样在板级文件里硬编码而是通过设备树节点来匹配。一个典型的以太网节点长这样ethernetfe300000 { compatible rockchip,rk3399-gmac; reg 0x0 0xfe300000 0x0 0x10000; clocks cru SCLK_MAC; phy-mode rgmii; phy-handle phy0; mdio { #address-cells 1; #size-cells 0; phy0: ethernet-phy1 { reg 1; }; }; };compatible决定用哪个 MAC 驱动phy-mode告诉驱动接口是 RGMII 还是 RMIIphy-handle指向 MDIO 总线下的 PHY 节点reg 1就是 PHY 的 MDIO 地址。这些信息在 U-Boot 启动时被解析驱动据此完成初始化和后续的 PHY 读写。我踩过的一个坑是设备树里phy-mode写成了rgmii-id但硬件上 PHY 和 MAC 之间没有延迟要求结果链路能起来但丢包严重。后来改成rgmii并确认 PHY 内部延迟配置问题才消失。所以设备树不是随便抄的必须和原理图、PHY 手册对一遍。1.4 从命令行到网线一次 ping 的完整路径理解整体架构后我们追踪一次ping命令的完整流程这样后面调试时就知道该在哪一层下功夫。用户在 U-Boot 命令行输入ping 192.168.1.100。net 层解析参数构造 ICMP 请求包封装成以太网帧目标 MAC 先查 ARP 缓存没有就发 ARP 请求。net 层调用eth_device的send回调把帧交给 MAC 驱动。MAC 驱动把帧数据写入发送描述符配置 DMA 地址启动发送。MAC 硬件通过 RGMII/RMII 接口把数据发给 PHY。PHY 完成并串转换和电平驱动把信号送上网线。对端回复后PHY 恢复出时钟和数据MAC 接收描述符收到帧触发轮询或中断。MAC 驱动把帧交给 net 层net 层解析 ARP 或 ICMP 回复打印结果。这条路径上任何一步出问题现象可能都是“ping 不通”但根因完全不同。所以调试时不能瞎猜要按层排查。2. MAC 与 PHY 之间的 MDIO 通信细节2.1 MDIO 总线的物理层与协议层MDIO 是 MAC 和 PHY 之间的管理接口两根线MDC 是时钟MDIO 是双向数据。它不属于以太网数据通道而是独立的管理通道。MAC 通过它读写 PHY 的寄存器完成自协商启动、链路状态读取、速率双工查询。协议上一次 MDIO 读写包含前导码32 个 1、起始码01、操作码10 读 / 01 写、PHY 地址5 位、寄存器地址5 位、 turnaround2 位、数据16 位。总共 64 个 MDC 周期。U-Boot 的 MAC 驱动通常提供mdio_read和mdio_write两个底层函数PHY 框架再基于它们封装出phy_read和phy_write。这里有个容易忽略的点MDC 时钟频率不能太高。IEEE 802.3 规定最大 2.5 MHz但很多 SoC 的分频器算下来可能到 5 MHz 甚至更高。短时间读写可能没事但长时间自协商或者频繁轮询时PHY 可能响应异常。我在一块全志板子上遇到过 MDC 过快导致 PHY 寄存器读回全 0 的情况把分频系数调大一倍就正常了。2.2 PHY 地址扫描与设备树配置PHY 地址由硬件决定通常通过 PHY 芯片上的几个引脚上下拉来设定。地址范围 0 到 31。设备树里reg 1就是告诉驱动去地址 1 找 PHY。如果地址配错现象是phy_read返回0xffff或者0x0000。这时候可以用 U-Boot 的mdio命令手动扫描mdio list mdio read 0 0 mdio read 1 0 mdio read 2 0读寄存器 0BMCR和寄存器 1BMSR正常应该返回非全 0 或全 1 的值。如果某个地址读出来是0xffff说明那个地址没有 PHY 或者 MDIO 通信本身有问题。我一般会先确认 MDIO 总线是否通读一个已知存在的 PHY 地址如果全是0xffff先查 MDC 时钟、MDIO 上拉电阻、PHY 供电。如果读出来有值但不对再查地址是否匹配。2.3 自协商流程与常见卡死原因PHY 上电后默认进入自协商状态。MAC 驱动通过 MDIO 写 BMCR 寄存器的 bit 12 和 bit 9 来启动自协商然后轮询 BMSR 的 bit 5自协商完成和 bit 2链路状态。自协商卡死是调试中最常见的问题之一。原因通常有这几类PHY 供电或复位异常PHY 没正常复位寄存器处于未知状态。检查复位 GPIO 时序确保复位脉冲宽度符合手册要求。MDIO 通信失败前面说的时钟、上拉、地址问题。对端不支持自协商有些老交换机或固定配置的对端设备需要强制设置速率双工。这时候要关掉自协商手动写 BMCR 配置 100M 全双工或 10M 半双工。PHY 模式配置错误RGMII 需要 TX/RX 延迟RMII 需要 50MHz 参考时钟。这些在设备树和 PHY 寄存器里都要配对。U-Boot 里可以通过phy命令查看和修改phy list phy read 1 0 phy write 1 0 0x11400x1140是关自协商、100M 全双工、启动协商的典型值。具体值要查 PHY 手册。2.4 链路状态检测与速率双工确认自协商完成后驱动会读 BMSR 和 PHY 特定状态寄存器比如寄存器 10 或 17不同厂家不一样来确认实际协商结果。U-Boot 启动日志里通常会打印eth0: ethernetfe300000 PHY: 1 - Link is Up - 1000/Full如果只打印Link is Down说明物理链路没通。先查网线、对端设备、PHY 供电。如果链路 Up 但速率不对比如协商成 100M 而硬件支持 1000M要查 RGMII 延迟配置和 PHY 的千兆控制寄存器。我遇到过一次协商成 100M 的情况最后发现是 PCB 上 RGMII 的 TX 和 RX 走线长度差异太大导致千兆时序不满足。这种硬件问题只能改板软件上可以尝试调整 PHY 内部延迟来补偿但不是长久之计。3. U-Boot 网络驱动实操配置流程3.1 环境准备与编译配置在动手改驱动之前先把编译环境搭好。U-Boot 的配置系统基于 Kconfig网络相关的选项在configs/目录下的板级配置文件和drivers/net/Kconfig里。关键配置项CONFIG_NETy CONFIG_CMD_NETy CONFIG_CMD_PINGy CONFIG_CMD_TFTPBOOTy CONFIG_CMD_DHCPy CONFIG_PHYLIBy CONFIG_PHY_GIGEy CONFIG_DM_ETHy CONFIG_ETH_DESIGNWAREyCONFIG_DM_ETH启用驱动模型CONFIG_PHYLIB启用通用 PHY 框架CONFIG_PHY_GIGE支持千兆 PHY。具体 MAC 驱动根据 SoC 选择比如CONFIG_ETH_DESIGNWARE是 Synopsys DesignWare MAC很多 SoC 都用这个 IP。编译make ARCHarm CROSS_COMPILEaarch64-linux-gnu- defconfig make ARCHarm CROSS_COMPILEaarch64-linux-gnu- -j$(nproc)编译完烧录到板子启动后进 U-Boot 命令行先确认网络设备被识别eth list如果没有任何设备说明驱动没匹配上或者设备树节点没启用。3.2 设备树节点编写与 PHY 参数设置设备树是驱动匹配的入口。以 RGMII 接口为例一个完整的以太网节点需要包含compatible匹配 MAC 驱动regMAC 寄存器基地址和长度clocks和clock-namesMAC 时钟phy-mode接口模式phy-handle指向 PHY 节点mdio子节点包含 PHY 地址PHY 节点里除了reg还可以加reset-gpios、reset-assert-us、reset-deassert-us来控制复位时序。有些 PHY 需要额外的qca,clk-out-frequency或realtek,led-link之类的厂家属性。我一般会先在设备树里把 PHY 地址写成扫描到的值phy-mode按原理图填然后编译启动看日志。如果 PHY 识别失败先查mdio命令能不能读到寄存器再查设备树节点是否被status okay启用。3.3 手动设置 IP 与 tftp 下载验证网络设备识别后先手动配 IP 验证基本连通性setenv ipaddr 192.168.1.10 setenv netmask 255.255.255.0 setenv serverip 192.168.1.100 setenv gatewayip 192.168.1.1 ping 192.168.1.100ping通说明 MAC、PHY、net 三层都正常。然后测试 tftptftp 0x40000000 test.bin如果ping通但tftp失败通常是服务器配置问题或者防火墙拦截。检查 tftp 服务是否启动、目录权限、文件是否存在。如果ping不通按层排查eth list看设备是否存在mdio list看 PHY 是否被识别phy read看寄存器值是否正常看启动日志里 PHY 链路状态查网线和对端设备3.4 从 tftp 到 nfs 启动的完整链路实际产品开发中U-Boot 网络最终要服务于内核和根文件系统的加载。典型流程setenv bootargs consolettyS0,115200 root/dev/nfs rw nfsroot192.168.1.100:/nfsroot ip192.168.1.10 setenv bootcmd tftp 0x40000000 Image; tftp 0x50000000 dtb; booti 0x40000000 - 0x50000000 saveenv boot这里tftp加载内核和设备树booti启动。根文件系统通过 NFS 挂载。整个链路依赖 U-Boot 网络正常工作。我建议在量产前把bootcmd和bootargs固化到环境变量里并测试断电重启后能否自动完成。有些板子环境变量保存在 eMMC 或 SPI Flash 里要注意保存介质是否可靠。4. 常见故障排查与实战经验4.1 PHY 识别失败的五种典型原因PHY 识别失败是 U-Boot 网络调试中最常见的问题。根据我的经验按概率排序现象可能原因排查方法mdio read返回 0xffffMDIO 无通信查 MDC 时钟、上拉电阻、PHY 供电mdio read返回 0x0000PHY 未复位或地址错查复位 GPIO、扫描所有地址能读到值但驱动不匹配compatible 不对查 PHY ID 和驱动支持列表链路始终 Down网线或对端问题换网线、换交换机、查 PHY 供电协商速率不对RGMII 延迟配置错查设备树 phy-mode 和 PHY 寄存器我遇到最多的是 MDIO 上拉电阻缺失。有些硬件设计为了省料MDIO 线上没加上拉短距离可能能用但稍微长一点或者干扰大一点就通信失败。补一个 1.5K 到 10K 的上拉电阻通常能解决。4.2 ping 不通的分层排查法ping不通时不要慌按层排查效率最高第一层设备是否存在eth list没有设备查驱动和设备树。第二层PHY 是否识别mdio list phy list没有 PHY查 MDIO 和地址。第三层链路是否 Up看启动日志或phy read读 BMSR。第四层IP 配置是否正确printenv ipaddr serverip netmask确认 IP 和服务器在同一网段。第五层ARP 是否通ping时如果 ARP 没回复说明二层不通。可以尝试arp命令查看缓存。第六层对端是否可达换一台电脑直连测试排除交换机或路由器问题。这套方法我用了很多年基本能覆盖 90% 以上的网络问题。4.3 速率双工不匹配导致的丢包问题链路 Up 但丢包严重很多时候是速率双工不匹配。一端自协商成千兆全双工另一端强制百兆半双工结果就是大量冲突和丢包。排查方法phy read 1 0 phy read 1 1 phy read 1 10寄存器 0 是 BMCR寄存器 1 是 BMSR寄存器 10 是 PHY 特定状态。对比两端协商结果如果不一致要么都开自协商要么都强制相同配置。我一般建议两端都开自协商除非对端设备不支持。如果必须强制确保两端速率双工完全一致。4.4 U-Boot 网络性能优化的小技巧U-Boot 网络性能通常不是重点但在大批量烧录或快速启动场景下提升 tftp 速度能省不少时间。几个可调的点增大 DMA 描述符数量减少等待提高吞吐。启用校验和卸载如果 MAC 支持让硬件算 IP 和 TCP/UDP 校验和。调整 MDC 时钟在 PHY 能接受的范围内适当提高加快寄存器访问。使用千兆模式确保 PHY 和 MAC 都工作在千兆别协商成百兆。我在一块 i.MX6 板子上把 tftp 速度从 8MB/s 提到 11MB/s主要就是确认了千兆协商和增大描述符环。4.5 环境变量保存与网络启动自动化调试完成后把网络配置固化到环境变量setenv ipaddr 192.168.1.10 setenv serverip 192.168.1.100 setenv gatewayip 192.168.1.1 setenv netmask 255.255.255.0 setenv bootcmd tftp 0x40000000 Image; tftp 0x50000000 dtb; booti 0x40000000 - 0x50000000 saveenvsaveenv把变量写到持久存储。注意有些板子的环境变量分区可能没配置好保存会失败。检查CONFIG_ENV_IS_IN_MMC或CONFIG_ENV_IS_IN_SPI_FLASH是否启用以及对应的设备号和偏移量。我习惯在量产前做一次断电重启测试确认环境变量真的保存成功避免批量生产时每块板子都要手动配置。5. 从 U-Boot 到内核的网络衔接5.1 内核启动后网络设备的接管U-Boot 把内核加载起来后网络设备的控制权要交给 Linux 内核。这个过程不是自动的需要内核驱动重新初始化 MAC 和 PHY。U-Boot 里配置的 IP 地址、PHY 状态通常不会直接传给内核除非用ip参数或者设备树里的fixed-link节点。常见做法是在bootargs里指定ip192.168.1.10:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off这样内核启动后会自动配置 eth0 的 IP并尝试 NFS 挂载根文件系统。5.2 设备树在 U-Boot 和内核之间的复用同一份设备树通常同时给 U-Boot 和内核使用。但有些属性只对 U-Boot 有意义比如u-boot,dm-pre-reloc有些只对内核有意义比如interrupts。编写时要注意区分避免互相干扰。我一般会把公共部分放在一个.dtsi里U-Boot 和内核各有一个顶层.dts包含它再各自添加特定属性。这样维护起来清晰也不容易出错。5.3 网络启动失败时的回退策略网络启动不是万无一失的。服务器挂了、网线松了、交换机重启了都可能导致启动失败。所以量产设备通常要有回退策略本地存储启动eMMC 或 SPI Flash 里存一份可启动的镜像。USB 启动插 U 盘或连 USB 线就能恢复。串口下载最差情况下用串口传一个小系统进去。U-Boot 的bootcmd可以写成多级尝试setenv bootcmd if tftp 0x40000000 Image; then tftp 0x50000000 dtb; booti 0x40000000 - 0x50000000; else run mmcboot; fi这样网络失败时自动从 eMMC 启动提高可靠性。5.4 实际项目中踩过的三个坑第一个坑PHY 复位 GPIO 被其他驱动占用。设备树里 PHY 节点写了reset-gpios但同一个 GPIO 在别的地方也被引用导致复位时序混乱。解决办法是检查所有引用确保独占。第二个坑MDIO 总线上挂了多个 PHY地址冲突。一块板子有两个网口两个 PHY 地址配成一样结果只能识别一个。改硬件跳线或者用 MDIO 的phy-handle分别指定。第三个坑U-Boot 网络正常内核网络不通。原因是内核驱动没有正确配置 RGMII 延迟而 U-Boot 里配了。检查内核设备树的phy-mode和 PHY 驱动里的延迟设置确保一致。这三个坑我都实际遇到过每一个都花了不少时间排查。写出来是希望大家少走弯路。6. 调试工具与命令速查6.1 U-Boot 网络相关命令一览命令作用常用示例eth list列出网络设备eth listmdio list列出 MDIO 总线mdio listmdio read读 PHY 寄存器mdio read 1 0mdio write写 PHY 寄存器mdio write 1 0 0x1140phy list列出 PHY 设备phy listphy read读 PHY 寄存器phy read 1 0phy write写 PHY 寄存器phy write 1 0 0x1140ping测试连通性ping 192.168.1.100tftp下载文件tftp 0x40000000 file.bindhcp动态获取 IPdhcpnfs挂载 NFSnfs 0x40000000 192.168.1.100:/nfsroot这些命令在调试时非常有用建议先help看一遍用法。6.2 关键寄存器速查与含义寄存器地址关键位含义BMCR0bit 15复位BMCR0bit 12自协商使能BMCR0bit 9重启自协商BMSR1bit 5自协商完成BMSR1bit 2链路状态PHYID12全部PHY ID 高 16 位PHYID23全部PHY ID 低 16 位ANAR4全部自协商通告ANLPAR5全部对端自协商通告读 PHY ID 可以确认 PHY 型号读 ANLPAR 可以看对端支持的能力。6.3 日志分析与问题定位U-Boot 启动日志里网络相关的部分通常长这样Net: eth0: ethernetfe300000 PHY: 1 - Link is Up - 1000/Full如果只有Net: eth0: ...没有 PHY 行说明 PHY 没识别或者链路没起来。如果 PHY 行显示Link is Down查物理连接。如果显示速率不对查协商配置。我习惯把完整启动日志保存下来出问题时对比正常和异常的差异往往能快速定位。6.4 硬件层面的检查清单软件排查完还没解决就要看硬件了。检查清单PHY 供电是否正常通常 3.3V 或 1.8V复位 GPIO 时序是否符合手册MDC/MDIO 上拉电阻是否焊接RGMII/RMII 走线是否等长晶振是否起振25MHz 或 50MHz网口变压器是否正常RJ45 连接器是否虚焊我遇到过一块板子 PHY 供电正常但复位引脚悬空导致 PHY 一直处于复位状态。补一个上拉电阻就好了。6.5 常用调试命令组合快速排查网络问题我一般按这个顺序敲eth list mdio list phy list mdio read 1 0 mdio read 1 1 ping 192.168.1.100五条命令下来基本能判断问题在哪一层。如果mdio read返回0xffff直接查硬件如果返回正常值但ping不通查 IP 配置和对端设备。这套流程我在多个项目上用过效率很高。希望对你也有帮助。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →