4. 基本寄存器1(BMSR):状态寄存器的位定义

BMSR,全称是 Basic Mode Status Register,地址为 0x01。这是 PHY 芯片里最常用的状态寄存器之一。我个人的习惯是,每次拿到一块新的板子,先读这个寄存器,看看 PHY 的基本健康状况。

说白了,它就像一个“体检报告”。告诉你物理层有没有连上,自协商跑没跑完,有没有检测到远端错误。面试的时候,面试官经常会问:“你怎么判断网线插没插好?” 答案就在 BMSR 里。

4.1 BMSR 寄存器位定义速览

BMSR 是一个 16 位的寄存器,但真正用到的位并不多。很多位是保留位,读出来永远是 0。咱们只看核心的几位。我习惯把它的位定义整理成一张表,方便快速查阅。

位 (Bit) 名称 描述 我常用的调试场景
15 100BASE-T4 支持 T4 模式(基本不用管) 忽略,现在几乎见不到
14 100BASE-TX 全双工 支持 100M 全双工 确认 PHY 能力
13 100BASE-TX 半双工 支持 100M 半双工 确认 PHY 能力
12 10BASE-T 全双工 支持 10M 全双工 确认 PHY 能力
11 10BASE-T 半双工 支持 10M 半双工 确认 PHY 能力
9 100BASE-T2 全双工 支持 T2 模式(基本不用管) 忽略
8 100BASE-T2 半双工 支持 T2 模式(基本不用管) 忽略
6 MF 帧前缀抑制 管理帧处理能力 极少使用
5 自动协商完成 (AN Complete) 自协商流程结束,1 表示完成 ⭐ 核心调试位
4 远端错误 (Remote Fault) 对端 PHY 报错 ⭐ 定位链路对端问题
3 自动协商能力 (AN Ability) PHY 是否支持自协商 确认 PHY 功能
2 链接状态 (Link Status) 1 表示链路建立,0 表示断开 ⭐ 最最核心的调试位
1 Jabber 检测 检测到超长帧 排查特定问题
0 扩展能力 是否支持扩展寄存器 确认是否需要读扩展寄存器

核心要点: 在实际调试中,你只需要关注 Bit 5(自动协商完成)、Bit 4(远端错误)和 Bit 2(链接状态)。其他的位,大部分时候你看都不用看。

4.2 链接状态位 (Bit 2) - 最常用的“心跳”信号

这个位,我几乎每天都在用。它就是 PHY 的“心跳”。值为 1,说明物理层已经和对方协商好了链路。值为 0,就是网线没插好或者对面没开机。

特点: 这个位是锁存的 (Latching)。什么意思?就是当链路断开时,它立刻变成 0。但当你重新插上网线,它不会立刻变回 1。你必须读一次寄存器,它才会更新。这是一个很经典的“陷阱”。

⚠ 避坑指南: 我曾经在调试一个交换机项目时,发现链路明明已经恢复了,但软件一直报 Link Down。折腾了半天,发现是驱动代码只读了一次寄存器。解决方案是:连续读两次 BMSR,丢弃第一次的结果,用第二次的值来判断。你想想看,很多面试题就喜欢考这个点。

// 正确的读链接状态流程
uint16_t bmsr_val;
// 第一次读,清除锁存位
bmsr_val = phy_read(phy_addr, 0x01);
// 第二次读,获取真实状态
bmsr_val = phy_read(phy_addr, 0x01);

if (bmsr_val & (1 << 2)) {
    printf("Link is UP\n");
} else {
    printf("Link is DOWN\n");
}

4.3 自动协商完成位 (Bit 5) - 自协商的“终点线”

这个位告诉你,自协商流程是否已经跑完了。值为 1,表示双方已经商量好了速率和双工模式。如果自协商没完成,你读到的速率和双工模式寄存器是无效的。

面试常见问题: “你怎么知道自协商完成了?” 答案就是读这个位,而不是去读自协商能力寄存器。

我的经验是:在驱动初始化时,不要假设自协商一下子就完成。需要轮询等待这个位置 1。通常需要等待 1-3 秒。如果等了很久还是 0,那就要考虑硬件问题了,比如网线质量差,或者对端不支持自协商。

// 等待自协商完成的轮询代码
int wait_for_an_complete(uint8_t phy_addr, int timeout_ms) {
    uint16_t bmsr;
    while (timeout_ms > 0) {
        bmsr = phy_read(phy_addr, 0x01);
        if (bmsr & (1 << 5)) {
            return 0; // 成功
        }
        delay_ms(100);
        timeout_ms -= 100;
    }
    return -1; // 超时失败
}

4.4 远端错误位 (Bit 4) - 对端 PHY 的“求救信号”

这个位比较有意思。它不是一个本地状态,而是对端 PHY 通过 FLP 脉冲发给你的。说白了,就是对面的 PHY 出问题了,通知你一声。

什么情况下会触发?

  • 对端链路断开: 如果对端 PHY 检测到自己的链路丢了,它会发远端错误。
  • 对端自协商失败: 对端 PHY 自协商没能达成一致。
  • 对端 PHY 进入低功耗模式: 某些节能模式会触发这个。

💡 调试技巧: 当你的板子和对端设备死活连不上时,如果读到的链接状态是 0,但远端错误位是 1,那问题很可能出在对端。我曾经遇到一个案例,板子连交换机死活连不上,读远端错误位为 1。最后发现是交换机的那个端口被管理员 shutdown 了。所以,这个位能帮你快速定位问题是出在本地还是对端。

4.5 BMSR 与其他状态寄存器协同

光读 BMSR 还不够,它只是给你一个高层次的概览。想要拿到具体的速率和双工模式,你还需要配合其他寄存器。这里我画了一张流程图。

BMSR 寄存器调试流程 BMSR 寄存器调试流程 开始调试 读取 BMSR (addr=0x01) 检查 Bit 2 (Link Status) Link=1 读 BMSR 确认 AN 完成 Link=0 检查远端错误位 结合 AN 能力与伙伴能力寄存器,确认工作模式 切记:先连续读两次

这张图展示了我的调试思路。第一步永远是读 BMSR,看链接状态。如果没连上,马上看远端错误位,初步判断是本地还是对端问题。如果连上了,再进一步确认自协商是否完成,最后再去读其他寄存器确认具体的速率和双工模式。

4.6 面试常见问题与举例

我整理了几个面试中高频出现的 BMSR 相关问题。你在准备的时候,可以重点看看。

  1. 问题: BMSR 的 Bit 2 (Link Status) 是锁存的,如何正确读取?
    回答: 连续读两次,第一次用于清除锁存状态,第二次读取真实值。这是必考的,答应我别踩坑。
  2. 问题: 自协商没完成,但链接状态却为 1,可能吗?
    回答: 可能。比如强制设置了速率和双工模式,不经过自协商也能 Link Up。这时 BMSR 的 Bit 5 会是 0。
  3. 问题: 如何区分是本地 PHY 坏了还是对端设备坏了?
    回答: 读 BMSR。如果本地链接状态为 0,同时远端错误位 (Bit 4) 为 1,大概率是对端的问题。
  4. 问题: BMSR 的高位 (Bit 15-11) 有什么作用?
    回答: 这些位表示 PHY 支持的工作模式。比如 100BASE-TX 全双工。一般用于初始化时确认 PHY 的能力。

总结: BMSR 是 PHY 调试的入口。我的习惯是,遇到网络不通的问题,第一个读的就是它。记住它的核心三位:Bit 2(链接状态)、Bit 5(自协商完成)、Bit 4(远端错误)。把这三位吃透了,你能解决 80% 的物理层问题。