Linux内核的PHY子系统和MDIO总线,本质是围绕PHY芯片的一套标准化管理体系,严格遵循“设备-总线-驱动”的经典模型,核心就是让内核能精准识别、适配并管理各类PHY芯片,下面从核心构成到工作流程,一步步拆解。
一、核心构成:设备、总线、驱动三足鼎立
PHY子系统的核心就是三大模块,缺一不可,共同支撑PHY芯片的全生命周期管理:
- PHY设备:内核用`phy_device`结构体来描述每一个PHY芯片,里面装着芯片的关键信息,包括关联的MDIO总线、芯片的唯一ID、在总线上的地址,还有运行状态、速率、双工模式、链路情况,以及绑定的网络设备和中断配置等。使用前,必须先通过
`phy_device_register()`完成注册,而注册前要先调用`get_phy_device()`完成设备创建——这个函数会先读取PHY芯片的ID寄存器获取ID,判断设备真实存在后,通过`phy_device_create()`申请内存、初始化结构体,最终完成注册,让内核能识别设备。
- PHY驱动:驱动用`phy_driver`结构体定义,核心是一堆操作函数,比如软复位、初始化配置、自动协商、状态读取、休眠唤醒、中断处理等,编写驱动的关键就是实现这些核心函数,不用面面俱到,按需实现即可。
驱动开发完成后,要注册到内核,单个驱动用`phy_driver_register()`;如果厂商有多款相似的PHY芯片,用`phy_drivers_register()`一次性注册整个驱动数组,避免重复操作;不需要时,通过`phy_driver_unregister()`就能卸载。
- MDIO总线:它是连接设备和驱动的桥梁,核心使命就是完成PHY设备与PHY驱动的匹配,定义在`mdio_bus_type`中。
匹配时遵循三级优先级:优先用设备树匹配,检查设备兼容性;若驱动有自定义的`match_phy_device()`匹配函数,就直接用它;最后兜底是PHY ID匹配——驱动预设ID和掩码,设备读取芯片寄存器得到ID,用掩码筛选后比对,一致则匹配成功。
匹配成功的设备和驱动直接绑定,不成功就调用内核自带的通用驱动。
二、内核自带保障:通用PHY驱动
Linux内核出厂自带通用PHY驱动,无需额外开发,系统启动时通过`phy_init()`函数自动注册。这个通用驱动是个数组,包含两个核心驱动:一个是适配10M、100M、1000M的常规PHY驱动,另一个是适配10G高速场景的PHY驱动,名字分别是Generic PHY和Generic 10G PHY。
通用驱动的核心逻辑,是依托IEEE标准定义的寄存器,读取并配置PHY的基础状态,比如速率、双工模式、链路状态、自动协商参数,能搞定常规联网需求。实际开发中,很多厂商的专用驱动都会复用通用驱动的基础函数,既节省开发量,又能保证兼容性。
三、专用驱动实践:以LAN8720A为例
LAN8720A的专用驱动由SMSC厂商统一提供,存放在内核的`smsc.c`文件中,默认处于关闭状态,需要在内核配置菜单里找到“Drivers for SMSC PHYs”选项并选中,编译后才能生效。
这款专用驱动采用混合开发思路:把自动协商、休眠唤醒这类基础功能,直接复用通用驱动的函数;而初始化配置、状态读取、中断响应这类特殊需求,则由厂商自定义实现,既复用内核成熟能力,又兼顾芯片的差异化功能。
驱动匹配的关键是芯片ID,LAN8720A的ID是0x0007c0f0,驱动的ID掩码是0xfffffff0,匹配时只比较高28位,忽略低4位的版本信息,让同系列的多款芯片能共用一个驱动,兼顾了适配效率和兼容性。配置生效后,系统就能精准识别并调用适配LAN8720A的专用能力,保障网络功能稳定发挥。
四、核心流程与价值
整个PHY子系统的运转流程很清晰:内核启动时先初始化MDIO总线和通用驱动;网卡驱动初始化时,MDIO控制器会扫描总线上的PHY设备,读取ID创建并注册设备;接着通过MDIO总线的三级匹配规则,优先匹配专用驱动,失败则回退到通用驱动;匹配完成后绑定驱动,配置基础能力,待网络接口开启后,自动完成协商、建立链路,实现联网。
之所以要启用LAN8720A的专用驱动,是因为通用驱动虽能满足基础联网,但无法支持中断、远程唤醒、精准链路检测、节能等高级功能,而专用驱动能完整激活这些特性,让芯片发挥全量性能,保障网络体验更完善。