1. 什么是PHY自协商?
当你把网线插入电脑或路由器时,有没有想过这两个设备是如何自动确定传输速度和双工模式的?这就是PHY自协商在默默发挥作用。简单来说,PHY自协商是物理层芯片(PHY)之间通过特殊脉冲信号自动协商最佳连接参数的过程,完全在硬件层面完成,不需要软件干预。
想象两个陌生人第一次见面握手时,通过握手的力度和方式就能判断对方的习惯——PHY自协商就是类似的"硬件握手"机制。它通过发送FLP(快速链路脉冲)或NLP(普通链路脉冲)来交换设备能力信息,最终选择双方都支持的最高性能模式。比如你的千兆网卡连接百兆交换机时,会自动降级到100Mbps速率,而不是直接连接失败。
这个过程完全由PHY芯片实现,与上层的MAC层无关。我在调试网络设备时经常遇到这种情况:明明接口显示"up",但传输速度异常缓慢,往往就是自协商失败导致的。这时候就需要深入理解FLP/NLP脉冲交互、寄存器状态变化这些底层机制,才能准确解决问题。
2. PHY自协商的完整工作流程
2.1 自协商的触发时机
PHY自协商会在三种情况下被触发:设备上电初始化、收到管理命令(比如ifconfig eth0 up)、或者用户手动重启自协商过程。这时PHY芯片会开始发送包含自身能力信息的FLP脉冲序列。我在实际项目中观察到,大多数商用PHY芯片默认都是开启自协商功能的。
FLP脉冲实际上是一组精心设计的电信号序列,每个脉冲间隔约16ms。这些脉冲不仅用于链路检测,还编码了设备支持的工作模式信息。接收方PHY会解析这些脉冲,提取出对端设备的连接能力。
2.2 能力交换与模式选择
当两端设备都支持自协商时,它们会互相解码对方的FLP脉冲,将对方的能力信息存储在对端能力寄存器中(PHY标准寄存器地址5)。同时,状态寄存器(地址1)的第5位会被置1,表示自协商完成。
选择最佳连接模式的逻辑其实很直观:
- 速率选择:如果两端都支持100M,就选100M;如果只有一端支持100M,就选10M
- 双工模式:优先选择全双工,只有当一方只支持半双工时才降级
我曾经遇到一个典型案例:办公室网络突然变慢,检查发现交换机端口协商为100M半双工,而网卡支持100M全双工。强制两端设为全双工后问题解决,这就是典型的自协商不匹配问题。
3. FLP与NLP脉冲详解
3.1 快速链路脉冲(FLP)
100M以太网使用FLP进行自协商,每个FLP突发包含33个时钟脉冲和17个数据脉冲。数据脉冲的位置表示特定的能力信息,比如:
- 脉冲1-5:基本能力(10M半双工、10M全双工等)
- 脉冲6:远端故障指示
- 脉冲7:确认收到能力信息
- 脉冲8-16:扩展能力(如1000M支持)
在调试时,用示波器观察这些脉冲波形是诊断自协商问题的有效手段。我曾通过这种方式发现过PHY芯片引脚虚焊导致FLP波形畸变的问题。
3.2 普通链路脉冲(NLP)
10M以太网使用更简单的NLP,每个脉冲间隔16ms±8ms。NLP主要用于链路检测,不携带丰富的协商信息。这也是为什么10M网络通常需要手动配置双工模式,而无法像100M/1000M那样智能协商。
4. PHY状态机与代码实现
4.1 Linux内核中的PHY状态机
Linux内核通过phy_state_machine状态机管理PHY的生命周期。这个状态机每隔HZ个jiffies(通常1秒)运行一次,处理各种状态转换:
enum phy_state { PHY_DOWN, PHY_READY, PHY_UP, PHY_NOLINK, PHY_RUNNING, PHY_HALTED };关键状态转换包括:
- PHY_UP:启动自协商(调用phy_start_aneg)
- PHY_RUNNING:持续检查链路状态(phy_check_link_status)
- PHY_HALTED:停止PHY工作
在实际调试中,我经常通过内核日志观察这些状态变化。比如看到PHY卡在UP状态不进入RUNNING,通常意味着自协商失败。
4.2 自协商的核心函数
phy_start_aneg是启动自协商的关键函数:
int phy_start_aneg(struct phy_device *phydev) { if (AUTONEG_DISABLE == phydev->autoneg) { phy_sanitize_settings(phydev); // 强制模式处理 } err = phy_config_aneg(phydev); // 配置自协商 if (phy_is_started(phydev)) { err = phy_check_link_status(phydev); // 检查链路状态 } }对于不支持自协商的老旧设备,内核会调用phy_sanitize_settings强制设置速度和双工模式。这也是为什么有些网络设备需要手动配置10M半双工才能工作。
5. 千兆以太网的特殊规则
千兆以太网的自协商与十兆/百兆有显著不同。802.3协议明确规定:
- 千兆PHY必须开启自协商功能
- 不能像十兆/百兆那样完全强制模式
- 协商过程需要确定主从时钟关系
这是因为千兆以太网采用更复杂的编码方案(如8B/10B),需要精确的时钟同步。在实际项目中,我曾遇到千兆光模块无法连接的问题,最终发现是因为一端关闭了自协商导致的。
6. 常见故障排查技巧
根据多年调试经验,我总结出PHY自协商问题的排查步骤:
- 检查物理连接:网线质量、接口氧化等问题最常见
- 查看寄存器状态:
- 寄存器1的bit5:自协商是否完成
- 寄存器5:对端设备能力
- 强制设置测试:临时强制设置速度和双工模式,确认是否是协商问题
- 示波器观察:检查FLP/NLP脉冲是否正常
有个记忆深刻的案例:某工厂设备网络时断时续,最终发现是附近大电机产生的电磁干扰导致FLP脉冲丢失。通过改用屏蔽网线解决了问题。
7. 寄存器操作实战
直接读写PHY寄存器是高级调试手段。以Marvell 88E1111 PHY为例:
# 读取基本状态寄存器(地址1) mii-tool -r eth0 0x1 # 读取对端能力寄存器(地址5) mii-tool -r eth0 0x5 # 强制设置为100M全双工 mii-tool -F 100baseTx-FD eth0在嵌入式开发中,我经常需要编写类似的寄存器操作脚本来自动化测试PHY功能。特别是在批量生产测试时,这种低层访问非常有用。
8. 硬件设计注意事项
设计含PHY的硬件时,有几个关键点容易出错:
- 复位电路:PHY需要稳定的复位信号,时间通常要求>1ms
- 时钟电路:25MHz/125MHz时钟的抖动要<50ps
- 电源滤波:PHY对电源噪声敏感,建议使用π型滤波
- PCB布局:MDI接口要尽量短,做好阻抗匹配
曾经有个项目因为忽略了电源滤波,导致PHY自协商成功率只有70%。添加了10μF+0.1μF去耦电容后问题解决。