2. PHY寄存器结构:标准与基本类型
寄存器的定义,说白了就是PHY芯片的“脑回路”。你调试网络不通、速率不对、自协商失败,最后都得回到寄存器层面找根源。我个人习惯是,拿到一个新PHY,先看它的寄存器map,而不是上来就跑测试。为什么呢?因为标准规定了底线,但每家厂商还有自己的“私货”。
好,咱们先聊聊标准。
2.1 遵循的标准——IEEE 802.3的“硬规矩”
大部分工业级PHY都遵循IEEE 802.3规范,具体来说是第22条(Clause 22)定义的MII(Media Independent Interface)管理接口。这个接口通过MDC(时钟)和MDIO(数据)两条线,就能读写PHY内部寄存器。
802.3里规定了几件事:
- 寄存器地址范围:0~31,但前16个(0~15)是“标准强制”的,谁家PHY都得有。
- 每个寄存器宽度:16位,这也是为什么你读出来的数值总是0x0000~0xFFFF。
- 地址0和地址1(控制/状态寄存器)的比特位定义是固定的——比如bit 15是复位,bit 13是速度选择等等。
当然,802.3还有Clause 45,用于更高速的PHY(千兆以上),地址空间更大(设备地址+寄存器地址两层),但基本思想一致。面试时,面试官通常只问Clause 22的寄存器结构,因为十有八九你调的是百兆或千兆PHY。
2.2 基本寄存器类型——0~15号寄存器
下面这张表是我手边常备的“速查手册”。你把它记熟了,80%的寄存器调试都能应付。
| 寄存器地址 | 名称 | 主要用途 |
|---|---|---|
| 0 (R0) | 控制寄存器 (Control) | 复位、回环、速度选择、自动协商使能、全双工等 |
| 1 (R1) | 状态寄存器 (Status) | 链接状态、能力、自协商完成、远程故障等 |
| 2 (R2) | PHY ID 低位 | OUI(组织唯一标识符)的低16位 |
| 3 (R3) | PHY ID 高位 | OUI高位 + 厂商型号 + 修订号 |
| 4 (R4) | 自协商通告 (Auto-Negotiation Advertisement) | 告诉对端我能支持哪些速率和双工模式 |
| 5 (R5) | 自协商对端能力 (Link Partner Ability) | 读取对端PHY通告的能力 |
| 6 (R6) | 自协商扩展 (Auto-Negotiation Expansion) | 对端是否支持自协商、下一页协商等 |
| 7 (R7) | 下一页协商 (Next Page) (可选) | 802.3扩展能力,比如EEE、流控 |
| 8~15 | 扩展状态 / 厂商自定义 | R8是扩展状态(千兆主从、1000BASE-T等),R9~R15多数厂家留着做扩展,或放具体误差计数器 |
你想想看,面试官最喜欢的开场问题就是:“PHY的基本寄存器0和1分别控制什么?” 如果你能按比特位背出来,基本就过关了。但光背不行,得理解怎么用。
举几个常用场景:
- 软复位:写R0的bit 15 = 1,然后等待bit 15自行清零(大概50ms),才算复位完成。我见过有人忘了轮询清零,直接读后续寄存器,读出一堆0xFF。
- 强制100M全双工:写R0,把bit 13设为1(100M),bit 12设为1(全双工),bit 12(自协商)设为0。注意,不同PHY对bit 0(自协商)与速率位的关系可能有微妙差别,最好先看手册。
- 读取链路状态:读R1,看bit 2(链接状态)。但很多PHY在链接断掉时,这个位可能不是立刻变0,需要读两次(两次值一致才算真的变)。这是IEEE建议的“去抖动”做法。
2.3 扩展寄存器与厂商自定义
地址16~31是留给厂商扩展的。你调驱动时,真正棘手的问题往往藏在这些“非标准”寄存器里。比如:
- LED控制寄存器:怎么改灯闪模式?
- 中断状态寄存器:当链接变化时,到底触发了哪个事件?
- MDI/MDIX交换控制:自动翻转模式是否开启?
- 千兆测试寄存器:像眼图参数、信号幅度调整。
我曾经维护过一个产品,在某个极端温度下千兆偶尔掉线。折腾了半个月,最后是在地址25(厂商自定义)里发现了“交叉耦合补偿阈值”的魔术位,调了一下就稳定了。所以说,别只盯着0~15,扩展寄存器才是真正体现“调试深度”的地方。
下面这张图把整个寄存器体系的结构画出来,你一看就明白:
看到没?整个体系分成三层:下层是标准的0~15,上层是扩展的16~31。调试时要分清楚,别拿扩展寄存器当标准用,也别以为标准寄存器在所有PHY上行为完全一致——事实上,各个厂商对某些比特位的实现细节会有差异。
2.4 面试常问的寄存器调试场景
最后归纳几个最常见的面试问题,你可以在回答时直接套用上面的知识:
- “PHY的软复位流程是什么?”
答:写R0 bit15=1,然后轮询读R0直到bit15为0(通常几到几十ms)。注意,复位后其他寄存器也会恢复默认值,特别是自协商使能位可能被复位。 - “怎么通过寄存器判断双绞线是直连还是交叉?”
答:先看厂商自定义寄存器中是否有MDIX状态位(通常地址16~31);如果支持自动翻转,读R1的某个厂商扩展位。没有的话,只能通过自协商结果和链路信号极性反推。 - “为什么我读R0想改速率,但写完之后链路断了?”
答:很可能在改写速率时,你没有关闭自协商(R0 bit12=0)。自协商开启时,速率位被内部逻辑锁定,写入会被忽略。我建议先读R0,修改对应比特,再写回去,不要直接整字赋值。 - “PHY ID有什么用?”
答:用于驱动匹配。Linux内核里很多PHY驱动就是根据R2和R3组合的PHY ID来绑定对应的驱动函数。如果ID不对,驱动可能加载错误,导致寄存器读写不匹配。
好了,这一章把寄存器标准、基本类型、实用场景都串起来了。下回你再碰到PHY调试,记得先查地址0和1,再翻厂商手册找扩展寄存器。结构化地读,比盲猜高效得多。