1. MDIO协议是什么为什么搞网络的人绕不开它做嵌入式网络开发的人天天跟PHY芯片打交道就绕不开MDIO。MDIO全称Management Data Input/Output也叫MII Management Interface是IEEE 802.3标准里定义的一种管理接口。它负责让MAC侧比如SoC里的GMAC控制器、交换机芯片、光模块的MCU去读写PHY芯片的寄存器从而完成速率协商、链路状态查询、环回测试、掉电管理、LED控制这些操作。说通俗一点PHY芯片就像一台设备的“网线感知器官”它能感知网线有没有插上、对端设备支持什么速率但这些感知结果不是凭空产生意义的必须让MAC侧把它读出来并根据结果去做配置。MDIO就是这条“大脑读取感知结果、下发调整指令”的神经通路。没有这条通路PHY芯片连自适应协商都没法正常触发网口就只能傻在那边。MDIO物理上只有两根线MDCManagement Data Clock管理时钟和MDIOManagement Data Input/Output管理数据。MDC由MAC侧提供是单向时钟输出MDIO是双向数据线读写时分时复用。这个设计和I2C有点像但比I2C简单没有地址ACK应答机制也没有设备热插拔检测帧格式完全是IEEE 802.3自己定义的一套。这篇文章我直接按实操路线来讲适合三种人看一是刚接触嵌入式网络、被PHY芯片驱动和寄存器搞得头疼的开发者二是硬件工程师想弄明白双网口共用一个MDIO该怎么设计、为什么有时候无法访问PHY三是做Linux系统适配的工程师遇到“PHY驱动加载正常但网口就是起不来”这类问题需要从MDIO层面排查。后面会涉及Linux下phy驱动、设备树、mdio总线注册这些实际工程问题也有纯硬件侧的参考设计经验和排查手法。2. MDIO协议栈核心原理拆解2.1 两根线是怎么把寄存器读出来的先看MDC和MDIO的分工。MDC是时钟源由MAC侧主动产生。IEEE 802.3规定MDC的最高频率是25MHz但实际工程里常见的是2.5MHz因为这个频率是10/100M以太网时代就定的老频率很多PHY芯片内部对这个频率做了同步逻辑跑太高反而容易出问题。还有一些SoC的MDIO控制器本身是挂在AHB/APB总线上的主频几百兆赫兹内部做了分频配置实际输出的MDC可以自由调但建议从低往高试不要上来就拉满。MDIO是数据线双向。在MDC的上升沿采样数据。PDPHY Device这边会把自己的寄存器数据在MDC下降沿之后、下一个上升沿之前准备好MAC侧在MDC上升沿去读。数据方向切换的时刻是帧尾这个后面讲帧格式时会细说。MDIO线需要接上拉电阻一般4.7kΩ到10kΩ都行。我见过不少板子因为MDIO上拉漏接导致读出来的PHY寄存器全是0xFF特别坑。正常工作时MDIO默认状态是高电平。如果拿示波器抓MDC波形能看到帧与帧之间有明显的空闲高电平时间。2.2 帧格式和读写时序细节MDIO帧格式由一个前导码开始整个帧结构是经典的五段式字段位宽说明PRE32位前导码全1用于同步ST2位起始码固定01OP2位操作码读是10写是01PHYAD5位PHY芯片地址0~31REGAD5位寄存器地址0~31TA2位状态转换位读帧是Z0写帧是10DATA16位数据读帧是PHY输出写帧是MAC输出有个细节很多资料不会强调前导码真的是32位全1。而且MDIO规范里允许一种“省略前导码”的帧格式叫“preamble suppression”或者“management frame without preamble”但这个功能不能在常规通信里默认开启否则控制器和PHY双方必须有同步机制。Linux内核里是有这个接口的但是你一般用不到也不建议用老老实实带全前导码最稳。读操作的时序是这样的MAC先输出32个1然后输出ST01、OP10、5位PHY地址、5位寄存器地址然后TA是2个bit第一个bit是高阻Z第二个bit是一个0紧跟着PHY侧接管数据总线输出16位寄存器值。总线切换的瞬间如果上拉电阻没接对或者PHY芯片的驱动能力太弱抓波形会看到第一个数据bit被拉到个很怪的电平后面那几位正常的现象。写操作的时序就简单一些OP是01TA是10然后MAC直接把16位数据发出去。PHY在MDC上升沿采样不需要ACK。所以读和写的核心区别在TA位和总线方向控制上。这也是初学者写FPGA的MDIO控制器时最容易翻车的地方很多人忘了把MDIO引脚切输入方向导致读出来的数据全是自己输出出去的旧值。2.3 寄存器模型标准寄存器与扩展寄存器PHY芯片内部寄存器映射是分“标准寄存器”和“扩展寄存器”两层结构的。标准寄存器就是IEEE 802.3规定的0~15号寄存器0号寄存器是控制寄存器BMCRbit 0.15是软复位bit 0.13是速率选择bit 0.12是自动协商使能bit 0.11是掉电bit 0.8是全双工/半双工选择。1号寄存器是状态寄存器BMSRbit 0.15是100BASE-T4能力bit 0.12是自动协商完成标志bit 0.9是10BASE-T全双工bit 0.8是10BASE-T半双工。2号和3号寄存器是PHY ID由OUI加型号加版本组成。4号、5号是自动协商对端能力寄存器和本地能力寄存器。6号寄存器是自动协商扩展状态。这些标准寄存器在IEEE 802.3的22.2.4章节里写得很细。做驱动开发的人必须把这些寄存器记得滚瓜烂熟因为Linux phylib里读取链路状态用的就是BMSR寄存器的bit 0.12触发自动协商就是改BMCR寄存器如果这些地址和bit位搞错驱动里的逻辑再好看也没用。扩展寄存器就五花八门了。每个PHY厂商都会在寄存器3~31之间预留一些然后在3~31之间塞自己的功能比如LED控制、环回模式、测试模式、省电模式、EEE功能配置等。更大的寄存器空间是通过“page”页的方式访问的先往寄存器0x1F写入一个page编号再访问0x10~0x1E这些普通寄存器访问到的就是对应page里的寄存器。这个机制是各厂商自定义的所以换PHY芯片之后扩展寄存器的驱动代码基本都要跟着改。锐捷、瑞昱、博通、Marvell这些厂家的PHY芯片都有自己的一套page机制。最坑的是有些芯片默认上电后指向的page不是0如果你驱动里没有显式切page就给扩展寄存器写值写进去的门影子寄存器可能是错的。2.4 MDIO时钟和时序容差IEEE 802.3里对MDC和MDIO之间的时序关系有明确要求但我实际测下来发现PHY芯片能容忍的时序范围比规范宽得多。规范的核心就是把MDIO数据的建立时间和保持时间管好数据变化必须跟MDC下降沿对齐这样MAC侧在上升沿采样的窗口最大PHY侧在下降沿后读数据的窗口也最宽裕。如果你是自己写FPGA逻辑实现MDIO主站最稳妥的实现方式就是把MDIO的bit数据在MDC下降沿前一点就准备好然后等MDC上升沿被采样。换言之数据动作描述为“下降沿驱动上升沿采样”。按这个原则写出来的代码基本不会出时序问题。如果你上来就按“上升沿驱动上升沿采样”去写就会看到奇怪的现象读回来的数据偶尔错一个bit用示波器单次抓又抓不到。PHY芯片地址的编号对应的是PHYAD引脚上拉/下拉的配置。RTL8211、KSZ9031这类常见芯片多是把PHYAD[4:0]引脚引出来板子上通过上下拉电阻设定地址。这个地址不能跟同一条MDIO总线上其他PHY冲突也不能跟MDIO控制器的“广播地址”冲突广播地址是0所有PHY都响应所以实际板卡上PHY地址一般都会避开0。3. Linux下MDIO总线和PHY驱动的实际工程玩法3.1 mdio-bus是怎么注册出来的在Linux内核里MDIO控制器被抽象成mdiobus。一个mdiobus对应一组物理上的MDC/MDIO引脚在这组引脚上可以挂多个PHY。内核里注册MDIO总线的路径一般有两种一种是通过设备树里的mdio节点另一种是SoC自带MDIO控制器的驱动直接调用mdiobus_register。做设备树时你会看到类似这样的结构mdio0 { status okay; phy0: ethernet-phy4 { reg 4; device_type ethernet-phy; }; };这个节点的用法就是告诉内核mdio0总线上地址为4的位置有个PHY叫phy0。之后以太网控制器比如MAC节点就可以通过phy-handle指向这个PHYgmac0 { status okay; phy-handle phy0; phy-mode rgmii-id; };这套机制成熟到你基本只需要保证设备树里的phy地址和硬件跳线一致其他交给phylib去做。但有个常见的坑很多SoC的MDIO控制器和以太网MAC控制器是绑在一起的比如你在设备树里disable了以太网MAC节点它的MDIO控制器也会变成禁用状态。结果就是PHY照样有复位、有时钟但MDIO总线根本不起作用PHY读不到。这种情况需要确认设备树里MAC节点和MDIO节点的状态控制逻辑。3.2 phylib驱动框架从probe到read_statusLinux的PHY驱动框架分两层一层是PHY lib自身的通用逻辑另一层是具体PHY芯片的驱动。前者处理的是所有PHY共性的东西比如自动协商的软件状态机、暂停帧能力协商、速率匹配等。后者处理的是厂商特有的功能比如Marvell的m88e1510驱动、瑞昱的RTL8211系列驱动。内核里PHY驱动注册的结构体大致长这样static struct phy_driver ks9131_driver { .phy_id 0x00221610, .phy_id_mask 0xfffffff0, .name Micrel KSZ9131, .config_init ksz9131_config_init, .config_aneg ksz9131_config_aneg, .read_status ksz9131_read_status, .suspend ksz9131_suspend, .resume ksz9131_resume, };phy_id匹配规则是MDIO读出的PHY ID寄存器值跟phy_id做掩码比对匹配成功就绑定这个PHY驱动。如果你换了PHY芯片但设备树里没有配置正确的compatible内核从MDIO读取的PHY ID会和驱动里的ID不匹配最终PHY就会回退到“通用PHY驱动”genphy。这种情况下十有八九链路能通但芯片特性功能全没启用。实际调试中我见过最典型的例子板子上用的PHY是千兆芯片但内核识别成genphy之后只协商出百兆速率抓破脑袋不知道原因。答案就是PHY驱动没匹配上。有一种做法可以验证是不是这个问题在驱动加载后手动读PHY ID寄存器看看读出来的值和PHY芯片手册上写的ID一不一致。内核提供了一堆调试手段最基础的是通过mdio-tools工具或者debugfs直接操作MDIO总线。3.3 不支持标准MDIO总线的SoC怎么访问PHY有些方案或SoC出来的时候MDIO控制器驱动不成熟或者MDIO控制器在某个平台上根本没有对应引脚这时候就得换路子访问PHY寄存器。热词里有个“linux phy 不使用mdio,使用i2c”这就是典型的替代方案。不少PHY芯片在有MDIO接口的同时还留了I2C从接口。比如RTL8211E没有I2C但BCM5461、KSZ9031、YT8010这些芯片内部逻辑就把MDIO的一部分寄存器也映射到了I2C接口上你完全可以通过I2C地址去读写PHY寄存器。在Linux下用I2C访问PHY的路径一般是设备树里把PHY挂到i2c总线上然后驱动里用i2c_master_recv / i2c_master_send这类接口去读写。i2c2 { status okay; phy0: ethernet-phy18 { reg 0x18; compatible microchip,ksz9031; }; };I2C访问PHY有一层天然的缺点I2C速率本身就比MDIO慢很多I2C标准速度100kbps高性能模式才400kbps而MDIO跑2.5MHz很轻松所以在要求频繁轮询PHY状态的交换机场景里用I2C代替MDIO会明显增加CPU开销。另外一个缺点是I2C没有MDIO那种“一次帧直接完成读16位寄存器”的巴适操作必须先写寄存器地址再读数据或者用I2C的重复起始位来一次性完成代码层面多绕一层。但这个方案也有正经的应用场景——有些光模块的DDM数字诊断监控信息就是通过I2C访问的SFP的管理接口本身就是I2C。如果设计一个模块同时要读光模块信息和PHY信息板子上就可以直接复用一条I2C总线硬件布线上省一组引脚这在空间受限的板卡上是个不小的优势。3.4 双网口共用一个MDIO的配置实例热词里专门有个“双网口共用一个mdio”这是一个很典型的硬件设计提法。现在很多SoC只有一组MDC/MDIO引脚但板卡要做两个网口两个PHY芯片就得串在这两条线上。先理清一个原则MDIO总线上可以挂多个PHY靠PHYAD区分。所以共用一个MDIO的核心问题就是两个PHY的PHYAD必须不同。硬件上怎么保证两个PHY芯片的PHYAD引脚一共5根分别接上下拉电阻做成不同的地址。比如PHY0地址设4PHY1地址设6。然后把两个PHY的MDC、MDIO引脚并联到SoC的MDC、MDIO引脚上每个PHY两边各自加上拉电阻。这样在Linux下设备树MDIO节点下就能挂两个PHYmdio0 { status okay; phy0: ethernet-phy4 { reg 4; }; phy1: ethernet-phy6 { reg 6; }; }; gmac0 { status okay; phy-handle phy0; phy-mode rgmii-id; }; gmac1 { status okay; phy-handle phy1; phy-mode rgmii-id; };这里有个坑必须强调两个PHY的PHYAD如果撞了则后注册的那个PHY会把先注册的覆盖掉或者产生“PHY地址冲突”的告警。在内核日志里你会看到类似“PHY 0x04 not found”或者识别出来的PHY ID对不上这时不要先怀疑驱动先用硬件测量确认PHYAD引脚的上下拉到底有没有生效。另外一个硬件坑是MDIO上拉电阻只能有一份不要两个PHY各放一个上拉这两个上拉并联之后电阻减半对驱动能力不足的MDIO主站是致命的。辅助的做法是在每个PHY的MDIO引脚上串联一个几十欧姆的电阻起到隔离和限流的作用防止某个PHY的故障把整条总线拖死。4. MDIO读写流程和寄存器配置实操记录4.1 从SoC寄存器操作到MDIO帧的调用链平时写Linux驱动你很少直接去操作MDIO控制器的寄存器但总有人问这样一个链路用户态想读一个PHY寄存器要经过哪几层先看一张通用调用链用户态mdio-tools / ethtool → Socket / ioctl → 网卡驱动 ethtool_ops → phylib mdiobus_read/mdiobus_write → MDIO控制器驱动如 stmmac_mdio_read / fsl_pq_mdio_read → 硬件寄存器如 MII_DATA、MII_ADDR → MDC/MDIO波形这里面最贴近硬件的是最后两层。以常见的Synopsys DesignWare MAC为例MDIO控制器有MII_ADDR和MII_DATA两个寄存器。发起一次读操作时先把PHYAD、REGAD、操作码写进MII_ADDR同时置busy位然后轮询MII_DATA里的busy位等待硬件把结果放进数据位。#define MII_ADDR_CR_REG_ADDR 0x00 #define MII_ADDR_PHY_ADDR (0x00 8) #define MII_ADDR_CR (0x01 30) #define MII_DATA_TA (0x02 2) #define MII_DATA_RA (0x01 30) #define MII_BUSY (0x01 0) static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) { unsigned int addr phyaddr 8 | phyreg; unsigned int data MII_DATA_TA | MII_BUSY | (phyreg 6); // 写入地址寄存器 writel(addr, priv-ioaddr GMII_ADDRESS); // 写入数据寄存器 writel(data, priv-ioaddr GMII_DATA); // 等待busy清零 while (readl(priv-ioaddr GMII_DATA) MII_BUSY) { udelay(10); timeout--; } return readl(priv-ioaddr GMII_DATA) 0xffff; }这段代码虽然简化过但核心流程是真实的写地址、写命令、轮询完成、读数据。要注意这里的MDC时钟频率是通过寄存器配置分频的不设置的话硬件可能直接按默认跑有些MAC默认分频是62.5MHz这时必须把MDC时钟配置到2.5MHz左右否则PHY芯片会不稳定。通常SoC的MDIO控制器时钟参考来自系统AHB时钟需要配置clk_div得到合适的MDC。4.2 用mdio-tools直接读写PHY寄存器Linux下有一款调试神器叫mdio-tools包含mdio和phytool两个工具。它的用法核心就是通过MII总线访问PHY的寄存器尤其适合在没有网卡驱动依赖的情况下直接把PHY寄存器读出来看看。典型用法# 列出当前系统所有MII总线 mdio list # 在bus 0上读取地址为4的PHY的寄存器1 mdio read 0 4 1 # 往地址为4的PHY的寄存器0写入0x1000比如关闭自动协商、设置千兆全双工 mdio write 0 4 0 0x1000第一次用这个工具的人很容易犯一个错把“bus编号”和“PHY地址”搞混。mdio list列出来的“0”是内核注册的bus序号比如stmmac-0后面的4才是PHY地址。不是所有的bus编号都以0开始具体得看 dmesg 里注册的bus id。如果你打算在项目里广泛使用mdio-tools最好先把每个PHY芯片的手册里常用寄存器列一个速查表比如爱用的0x00控制寄存器、0x01状态寄存器、0x1E扩展状态寄存器这样调试效率会高很多。4.3 从波形的角度确认读写是否正常就算你有驱动有工具读出来的值是错的也没法快速定位是链路时序问题还是寄存器配置问题。这时候就得上示波器抓MDC和MDIO波形。标准操作示波器两个通道CH1接MDCCH2接MDIO保证两个探头的地都接在同一个地参考上。触发模式设置成上升沿触发触发电平设在1.5V左右因为MDIO是3.3V电平。时间档设在20us/div左右这样能覆盖整个读帧和写帧。运行一次读寄存器操作比如mdio read 0 4 1抓一拍波形。正常读波形你会看到32个高电平脉冲组成的PRE段然后ST、OP、PHYAD、REGAD、TA这些字段在MDC上升沿被采样MDIO从高阻切换到驱动输出最后一个16位数据。注意在TA段第二个bit之后MDIO引脚的主人从MAC变成PHY波形上会有一个明显的方向切换痕迹。如果这里方向切换正常后续数据基本都对如果整个数据段都是固定的错误值且没有方向切换痕迹大概率是驱动代码忘了把引脚从输出切到输入。级联示波器的技巧是把MDC频率先降到最低可配置值来抓波形比如SoC MDIO控制器如果支持配置分频直接把MDC降到1MHz波形会更干净清晰方便数bit位。等逻辑对了再提上去确认高速稳定性。4.4 寄存器页切换的坑扩展寄存器为什么老是写不进去前面提过page机制这里具体展开一个实例。继续用Marvell的88E1512举例子它内部有page的概念。要访问一些扩展功能寄存器比如LED控制、基于寄存器的环回、EEE配置必须先把page切过去。访问流程# 从page 0切到page 2 mdio write bus phy 0x1F 0x0002 # 现在读0x10寄存器实际读的是page 2的0x10 mdio read bus phy 0x10写完之后要记得切回page 0否则后面所有normal寄存器的访问都会落在错误的页上表现就是链路时好时坏。很多人在驱动代码里写扩展寄存器只写一遍控制器就以为生效了结果换成板上电后自动协商结果跟配置不一致。这类问题排查思路就是先用mdio-tools手动切页、读写、切回复现问题然后跟驱动代码对比看缺了哪一步。大多时候是缺了切回page 0这一行。5. 双网口共享MDIO时踩过的那些坑5.1 地址冲突导致寄存器读写串扰双网口共用一个MDIO总线最大的坑就是两个PHY地址冲突。我做过一块双口网卡PCB上两个PHY的PHYAD配置为相同的地址逻辑上只有一条MDIO总线结果两个PHY都能识别但读出来的PHY ID和寄存器值明显相互干扰。你从MAC0的口读寄存器得到一个数据再从MAC1的口读同样地址读出来的ID变成另一个PHY的ID。原因是MDIO总线上的设备通过地址匹配响应MAC0发起的帧也会被两个PHY同时收到两个PHY地址一样就都试图输出数据MDIO线上的驱动互相打架。解决办法有两个方向硬件上改跳线地址或者软件上只挂一个PHY到MDIO总线、另一个改用其他管理通道。硬件改地址是首选成本最低、逻辑最清晰。5.2 PCBA上PHY芯片的复位时序对MDIO的影响在不少板卡上两个PHY芯片的复位引脚可能接到了同一个GPIO或者同一条复位信号线上。如果这些复位信号在上电时波形混乱比如毛刺比较多或复位完成时间长会出现一种情况MDIO控制器已经注册了总线但PHY芯片还处于复位状态MDIO读回来的寄存器全是0x0000或者0xFFFF。这个现象的迷惑性在于不是每次上电都复现而是有时能读到有效ID、有时不能。我的排查经验是先不接复位信号手动固定复位引脚电平强制PHY暂停复位然后用mdio读ID如果这时能稳定读到ID十有八九是复位时序的问题。再量一下复位引脚和MDC/MDIO上电的相对时序确认复位释放是否有足够的稳定时间。PHY芯片的datasheet里一般会给出“reset完成之后至少等待X毫秒才能进行MDIO访问”的说明。不过有的芯片要求短则10ms、长则150ms范围很大板子上如果RC延时不够或者复位信号控制逻辑设计粗糙就会导致上电后第一次MDIO访问总是失败。解决办法是驱动里对PHY做初始化时加一个固定延时或者在MDIO总线注册成功后主动对目标PHY做一次reset检测。5.3 总线电容和上拉电阻的搭配双PHY并联在同一条MDC/MDIO线上总线的电容负载会成倍增加。如果PCB走线太长线宽太细再叠加两个PHY芯片的引脚电容MDC的上升沿会被拉得特别缓。上升沿如果太缓超过PHY芯片手册里的最大上升时间要求采样时序就不对了表现出来的现象是低速比如把MDC配到1MHz能正常把MDC频率调到标准值之后就出现间歇性误码。解决办法有几个方向减小MDIO和MDC上拉电阻的阻值比如从10kΩ改成4.7kΩ能略微改善上升沿。缩短总线走线长度尽量做到等长MDC和MDIO不要相差太远。在PCB上给每个PHY的MDIO和MDC引脚各串一个33Ω的小电阻隔离负载减少反射。在SoC的MDIO控制器配置里调低MDC频率这是最后的兜底方案。我见过一辆量产设备PCB上双网口的MDIO走线绕了大半个板子导致两个PHY只能把MDC压到1.2MHz才能稳定读寄存器。这种问题后期特别难改板所以在硬件设计评审阶段就要把MDIO走线当高速信号来对待不要因为频率低就随便拉。频率低归低信号完整性照样有要求。5.4 MDIO总线复用器一种软件层的解决思路如果硬件上PHY地址确实冲突了但板子已经量产改不了硬件又想通过软件解决市面上有一种MDIO总线复用器的方案。这种芯片本身一端接主MDIO总线另一端扩展出多路MDIO子总线每一路可以单独接PHY从而用软件控制选择切换到哪一路。常见的如TI的SMI总线开关、NXP的MDIO mux、立锜这类厂商的“MDIO switch”芯片。Linux内核里对应的是mdio-mux框架。它的原理是把“父MDIO总线”抽象成一个mux总线每个子总线上挂的PHY地址可以一样因为访问子总线时通过mux芯片的寄存器先选择通道。设备树配置类似这样mdio-mux { compatible mdio-mux-gpio; pinctrl-names default; pinctrl-0 mdio_mux_pins; mux-gpios gpio1 6 GPIO_ACTIVE_LOW; mdio-parent-bus mdio0; mdio_mux_1: mdio0 { reg 0x0; #address-cells 1; #size-cells 0; phy_a: ethernet-phy1 { reg 1; }; }; };这个方案的问题是多了一次寄存器访问开销每次读写PHY寄存器都要先切通道性能有一定损耗。但在部分量产设备里这是唯一不改硬件就能解决地址冲突的办法。所以mdio-mux这个方向值得知道至少排查问题的时候你要能想到这个路子。6. MDIO无法正常工作时的排查手册6.1 八种典型故障现象与定位方法做MDIO调试多了很多问题都是重复的。我列一份故障排查速查表每一类问题都给出最直接的确认手段。故障现象可能原因确认方法读PHY ID全FFMDIO上拉缺失 / PHY未上电 / 复位未释放量MDC有无波形量PHY电源和复位引脚读PHY ID全00PHY地址总线短路到GND / 寄存器读时序方向不对量PHYAD引脚上下拉状态检查驱动方向切换逻辑偶尔能读通偶尔不能复位时序太短 / MDC过快给复位释放加延时降低MDC频率测试读回数据整体左移/右移一位MDIO方向切换时刻不准确 / 帧格式字段位错用示波器抓帧数bit位对照IEEE帧结构双网口两个PHY识别串扰两个PHY地址冲突分别断开一个PHY再看或用mux方案Linux下PHY驱动绑定失败PHY ID匹配不上 / 驱动没有注册查看dmesg里mdio bus枚举结果比对phy_id_maskethtool能看到PHY信息但没有link自动协商失败 / 对端未插线 / PHY模式配置错读BMSR寄存器看link bit检查phy-mode配置网口能协商千兆但吞吐量低MDIO访问异常导致EEE或节能功能异常用mdio-tools空闲读寄存器观察是否存在超时这些里最容易误导人的是第二种读全00。很多是PHY地址引脚被错误地全部下拉到地导致地址为0。IEEE规范里地址0是“广播地址”如果PHY地址设成0它会对所有不匹配的访问也产生响应导致总线上特别多的响应冲突。7. 关于MDIO调试工具链的个人经验建议7.1 示波器触发的进阶用法如果你手头有一台带宽足够的示波器用“总线解码”功能直接解码MDIO帧是很省力的。但先别高兴MDIO解码不是所有示波器都默认支持很多中低端示波器你只能靠手动数bit。手动数bit其实也不难关键是先定位帧的起始位置。MDIO帧的最前面是32个高电平的PRE所以你在屏幕上先找到一段很长的高电平脉冲段这段的末端就是PRE结束的地方后面紧跟着ST和OP的编码。ST固定是01OP读是10、写是01。数到ST之后的每一位按PHYAD、REGAD、TA、DATA的位宽切割就能把寄存器地址和值解出来。有次我调一块板子PHY读出来的ID总是不对示波器上数出MDIO帧的DATA字段是这样PHY输出的值和手调寄存器里的值完全一致但顺序颠倒才发现是FPGA里MDIO位序做了MSB/LSB反转硬件工程师又没在逻辑里统一。手动数bit在这种场景比任何工具都好用。7.2 逻辑分析仪更适合长序列分析示波器适合看单帧波形但如果你要在嵌入式Linux里持续监控MDIO总线上跑了哪些读、哪些写逻辑分析仪比示波器强太多。尤其是一台带协议解码的Saleae逻辑分析仪直接把MDC接CH0、MDIO接CH1打开MDIO协议解码器就能看到完整的帧序列哪个PHY地址、哪个寄存器、读写方向、数据内容。这个工具对排查驱动异常特别有效。比如怀疑驱动在启动阶段乱写PHY寄存器你可以上电抓一次完整启动流程把每次MDIO帧都解码出来跟代码里的调用点对照一下子就能定位是哪一行的操作导致PHY进入奇怪状态。逻辑分析仪的另一个好处是能长时间采集。有些软件问题不是固定复现的比如跑一小时之后PHY掉线你用示波器根本等不起逻辑分析仪开着让它录事后慢慢翻。7.3 ethtool和普通网络设备调试的关系大部分做网络开发的人排查网口问题第一步就是ethtool但很多人不知道ethtool底层也会访问MDIO。比如ethtool eth0这个命令它把MAC和PHY的协商状态全打出来底层就是读取BMSR寄存器的link状态位、BMCR寄存器的自动协商设置。如果你静态查看半天发现问题锁定在“网口link没起来”就该用mdio-tools直接读寄存器确认是PHY没协商成功还是MAC侧没有上报。这里有个特别的坑ethtool读到的link状态的是驱动缓存的不是实时的。ethtool eth0显示的“Link detected: yes/no”通常是phylib链路状态机轮询的结果轮询周期一般是2秒左右。如果你想要实时看到PHY寄存器的原始状态还得靠mdio直读。别在排查时盯着ethtool那行缓存不放容易误判时序问题。8. 写在最后的几条实际经验我自己这几年跟MDIO打交道的体会是MDIO这个协议本身简单到让人想当然但越是简单的接口在实际工程里越容易在细节上翻车。PHY地址跳线、上拉电阻、MDC频率、复位时序、Linux驱动匹配、设备树配置每一环都像多米诺骨牌倒一张全塌。给各位几个我个人亲测有效的建议第一拿到一块全新板子的第一件事先用示波器抓MDC有没有波形。没有波形一切都白搭别急着调驱动。第二在调试阶段别怕麻烦直接把mdio-tools编进你的根文件系统。它会帮你省掉大量“改驱动重新编译烧写”的重复劳动。第三多花半小时把要用的PHY芯片手册里的寄存器描述翻一翻重点记0号、1号、2号、3号这几组标准寄存器。很多看似诡异的现象读一读寄存器原始值答案自己就浮出来了。最后如果你准备把双PHY共用一个MDIO总线的方案定为量产设计强烈建议在原理图评审阶段就把PHYAD不同、上拉电阻唯一、复位时序可独立控制这三点列为强制检查项。这些在后期全是“改一次板子浪费时间”的痛点来源。
企业数字化 ERP 产品动态
相关推荐
个人知识库搭建指南:从笔记整理到高效复习 一、引言
在日常学习和工作中,我们每天都会接触大量信息。如何高效地积累、整理和运用这些知识,是提升学习和工作效率的关键。一个结构清晰的个人知识库,有助于快速检索信息、建立知识之间的联系,让复习和回顾更加高效。下面仅从工… · 2026/9/27 5:08:35
I2C地址扫描实战:100KHz总线测试与Excel记录方法 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 5:08:35
海思HI3798MV310机顶盒U盘强刷安卓9.0技术指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 5:08:29
江苏网站开发电话实战:3步搞定被黑挂马的最佳实践 江苏网站开发电话实战:3步搞定被黑挂马的最佳实践 网站突然打不开,浏览器弹出“不安全”红色警告,后台莫名多了几个陌生的管理员账号,或者首页代码里突然插满了博彩广告的跳转链接。遇到这种网站被黑挂马的情况,很多运营和推广人员第一反应是慌,不知道… · 2026/9/27 5:49:54
STM32H750 ADC+DMA+定时器配置避坑指南:从时钟树到校准的实战经验 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 5:49:48
参数小,不代表模型一定简单 在深度学习中,参数通常是网络在训练过程中学习得到的权重和偏置,它们可能只是接近于零的小数,例如零点几、零点零几,甚至更小。然而,单个参数数值较小,并不意味着整个模型只能完成简单的计算。一个深度神经… · 2026/9/27 5:49:48
网页设计专业大学排名避坑指南:别只看排名看落地 网页设计专业大学排名避坑指南:别只看排名看落地 别再盯着那些花里胡哨的模板网站了,丑到让人想删掉浏览器,更别提转化客户了。很多河北的中小企业老板,手里攥着几万块预算,却不知道该找谁做站,怕被坑,怕做出来的东西没人看。这篇避坑指南,不聊虚的,… · 2026/9/27 5:49:48
3d网站带后台下载踩坑实录:新手速查手册 3d网站带后台下载踩坑实录:新手速查手册 网站被黑挂马,后台登录页突然弹出博彩广告,这种噩梦谁没经历过?我见过太多湖南本地的小老板,花大价钱做的3D展示站,刚上线三天就变样了,找开发公司扯皮,对方推卸说是服务器问题,其实全是后台漏洞没补。别… · 2026/9/27 5:49:30
3个模拟wordpress工具,新手入门建站告别模板丑 3个模拟wordpress工具,新手入门建站告别模板丑 模板网站太丑不够用?很多安徽本地的项目经理跟我吐槽,花几千块买的建站模板,打开一看全是五颜六色的弹窗和过时的配色,客户看一眼就想换人。做项目最怕的就是这种“半成品”,改吧,没代码基础;… · 2026/9/27 5:49:17
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01