第1章:Phylink框架概述

1.1 什么是Phylink?

Phylink,说白了就是 Linux 内核里专门用来管理网络 PHY 设备的一个中间层框架。它的核心作用,是替网络驱动开发者搞定那些烦人的链路协商、速率切换、接口模式变更这类事情。

我刚开始接触这个框架的时候,也觉得它有点抽象。但你想想看,一个嵌入式网口要正常工作,背后有多少事要处理?PHY 芯片的初始化和配置、MAC 和 PHY 之间的接口模式(比如 RGMII、SGMII、1000BASE-X)怎么匹配、链路状态变了怎么通知上层……这些乱七八糟的事情,如果每个驱动都自己写一套,那得重复造多少轮子?

Phylink 就是来干这个的。它定义了一套标准化的 API 和回调函数,让 MAC 驱动只需要实现几个关键接口,剩下的链路管理杂活,全交给 Phylink 去协调。

一句话总结: Phylink = PHY 状态机 + 链路协商引擎 + MAC-PHY 适配层,打包成一个内核框架。

1.2 Phylink 的诞生背景——为什么要搞这个东西?

我记得几年前在做一款交换机芯片的驱动时,被 PHY 相关的代码折磨得不轻。那时候内核里已经有 phy 子系统了,但处理多路复用、SFP 热插拔、还有不同速率的下垂兼容这些问题,还是得自己手写大量胶水代码。

为什么会这样?因为传统的 PHY 驱动模型太「平」了。它假设你的 MAC 和 PHY 之间的关系是固定的、一对一的。可现实世界不是这样的:

  • 一个 MAC 可能接多个 PHY(比如通过交换芯片的端口复用)
  • PHY 可能支持多种接口模式,需要在运行时动态切换
  • SFP 模块插入后,要重新协商链路参数
  • 不同厂家的 PHY 芯片,行为模式差很多

这些场景,老的 phy 层处理起来就很吃力。所以从 Linux 4.x 开始,内核社区决定引入 Phylink——不是我说的,这事是真的。它最早是为了解决 Marvell 网卡驱动里那些复杂的链路管理问题,后来发现通用性很好,就进了主线。

一个小知识: Phylink 的作者 Russell King 也是个实战派。他在给 ARM 平台写网卡驱动时,发现不同板子的 PHY 连接方式五花八门,统一管理势在必行。

1.3 传统 PHY 驱动模式 vs Phylink——到底差在哪?

我们来做个对比。我用一个表格把关键差异列出来,这样更清楚:

对比维度 传统 PHY 驱动模式 Phylink 框架
链路协商管理 驱动自己写状态机 框架内置状态机,自动处理
接口模式切换 手动配置 MAC/PCS 层 通过回调统一管理
SFP/热插拔支持 需要额外逻辑 原生支持,回调通知
多 PHY 管理 容易混乱 集中调度
代码复用性 低,每个驱动重写 高,接口标准化
调试复杂度 高,链路问题难定位 中等,有统一日志出口

嗯,这里要注意一点:传统模式不代表不好,很多简单场景下它反而更直接。但当你的项目开始碰到「一个网口对应多个 PHY 设备」或者「需要支持不同速率下的接口模式自动切换」时,Phylink 的价值就体现出来了。

1.4 我们什么时候该用 Phylink?

我个人习惯的判断标准很简单——看你的硬件拓扑是否满足下面任意一条:

  1. MAC 和 PHY 之间不是固定的点对点连接(比如有复用器/交换芯片)
  2. 需要支持 SFP、SFP+ 这些可插拔模块
  3. PHY 支持多种接口模式,且需要在运行时切换(比如 RGMII ↔ SGMII)
  4. 想要让代码更容易移植到不同平台

但凡满足一条,我就建议你考虑用 Phylink。我曾经在一个项目里硬扛着用传统方式写,结果后期加 SFP 支持时改得想哭……从那以后,我再也不敢跳过 Phylink 了。

避坑提示: 如果你的项目只用一个固定的 PHY 芯片,且不涉及热插拔/速率切换,那用传统 phy 层就够了。Phylink 有额外的抽象开销,没必要为了用而用。

1.5 Phylink 的核心架构——一张图看懂

下面我用一张 SVGs 把 Phylink 在整个网络驱动栈里的位置和关系画出来。你一看就明白了:

Phylink 框架在 Linux 网络驱动栈中的位置 用户态:网络工具 / 应用 内核网络协议栈(TCP/IP 层) MAC 驱动(net_device_ops) 实现 ndo_open/stop/start_xmit Phylink 框架 状态机 / 链路协商 / 接口模式 回调注册 PHY 设备(PHY 驱动 / MDIO 总线) Marvell / Broadcom / Realtek / ... 硬件层:MAC + PHY 芯片 + 网络变压器 数据流方向:上 ← 下

从这张图可以看出,Phylink 是夹在 MAC 驱动和 PHY 设备之间的一个协调层。它向上给 MAC 驱动提供标准接口,向下通过 PHY 子系统和真实的 PHY 芯片打交道。当链路状态发生变化时,Phylink 自动跑状态机,然后回调通知 MAC 驱动做相应配置。

1.6 一个小例子:链路状态变化时发生了什么?

假设你的网口上插了一根网线,PHY 检测到 link up。在传统模式下,你得在 PHY 中断处理函数里手动调 MAC 的配置接口。在 Phylink 框架下,流程是这样的:

1. PHY 硬件检测到 link up
2. PHY 驱动通过 MDIO 读取状态寄存器
3. Phylink 状态机检测到变化
4. Phylink 调用回调:mac_link_up()
5. MAC 驱动在回调里配置 DMA、时钟、接口模式
6. 上层网络协议栈收到链路事件通知

你看,整个流程是由 Phylink 自动编排的。你只需要在 mac_link_up 回调里写清楚 MAC 侧要做什么就行。省心吧?

实战建议: 刚开始用 Phylink 时,我建议你先在 mac_link_up 和 mac_link_down 里打些调试日志。这样你能清楚地看到状态机是怎么跑的,出问题也好排查。

1.7 本章小结

Phylink 不是银弹,它解决的是一个特定范围的问题——复杂链路管理。它比你手写的状态机更可靠,比你拍脑袋的胶水代码更规范。当然,学习和理解它需要一点耐心,但一旦上手,你会发现很多重复劳动都被省掉了。