1. 课程导论:为什么需要设备树?网络设备驱动架构概览

1.1 为什么需要设备树?

在早期的 Linux 内核中(如 ARM 平台),板级硬件信息(内存基址、中断号、外设寄存器地址)被硬编码在 arch/arm/mach-xxx 下的 C 文件和头文件中。这种“代码即配置”的方式带来了严重的维护灾难:

  • 代码膨胀:每增加一块开发板,就要新增或修改大量 board-*.c 文件。
  • 内核与硬件耦合:更换一颗 PHY 芯片或调整 GPIO 引脚,必须重新编译内核。
  • 碎片化:同一 SoC 的不同评估板,驱动代码大量重复,社区难以维护。

设备树(Device Tree,DT)的引入彻底解决了上述问题。它将硬件描述从内核源码中剥离,形成一个独立的数据结构——.dts 源文件。内核在启动时解析设备树二进制(.dtb),动态创建 platform_device、i2c_client、spi_device 等内核设备对象,驱动只需匹配 compatible 字符串即可完成绑定。

核心转变: 从“代码描述硬件” → “数据描述硬件”。设备树是硬件拓扑的声明式语言,驱动只关心“如何驱动”,不再关心“硬件在哪里”。

1.2 网络设备驱动架构概览

一个完整的 Linux 网络设备驱动,从上到下涉及三个核心层次:MAC 层、MDIO 总线、PHY 层。它们之间的协作关系决定了网络数据包的收发质量。

架构口诀: MAC 负责数据链路层的帧封装与 DMA 传输,PHY 负责物理层的信号编解码与链路协商,MDIO 总线是 MAC 访问 PHY 寄存器的管理通道。

1.2.1 层次职责对比

层次 内核模块 核心职责 设备树节点
MAC drivers/net/ethernet/ DMA 描述符管理、帧过滤(RFS/RSS)、TSO/GRO 卸载 ethernet@xxx
MDIO 总线 drivers/net/phy/mdio-bus.c PHY 寄存器读写、扫描 PHY 地址、管理 PHY 状态机 mdio@xxx 或 mdio {}
PHY drivers/net/phy/ 链路协商(Auto-Neg)、速率/双工切换、信号检测 ethernet-phy@xx

1.2.2 网络设备驱动软件架构图

下图展示了从用户空间 socket 到物理网口的数据流,以及设备树节点在内核中的映射关系:

Linux 网络设备驱动架构与设备树映射 Linux 网络设备驱动架构与设备树映射 用户空间:socket / netlink 内核网络协议栈(TCP/IP) MAC 驱动层(stmmac / fec / dwmac) DMA 引擎 | 描述符环 | 中断处理 | NAPI ethernet@xxx compatible = "snps,dwmac" MDIO 总线(mdio-bus) PHY 寄存器读写 | 扫描 | 状态机管理 mdio@xxx {} #address-cells = <1> PHY 驱动层(Generic / Realtek / Broadcom) Auto-Neg | 速率/双工 | 链路状态中断 ethernet-phy@1 reg = <1>; 物理层(RJ45 / SFP / MII 总线) MAC 驱动 MDIO 总线 PHY 驱动 设备树节点 映射关系

1.3 设备树如何驱动网络设备绑定

设备树在网络驱动中扮演“硬件拓扑描述者”的角色。一个典型的千兆以太网设备树节点包含以下关键属性:

/* 设备树片段:MAC + MDIO + PHY 绑定示例 */
gmac0: ethernet@ff3e0000 {
    compatible = "snps,dwmac-4.20a";
    reg = <0xff3e0000 0x4000>;
    interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
    interrupt-names = "macirq";
    phy-mode = "rgmii";
    rx-fifo-depth = <4096>;
    tx-fifo-depth = <4096>;

    mdio0: mdio {
        #address-cells = <1>;
        #size-cells = <0>;
        compatible = "snps,dwmac-mdio";

        phy0: ethernet-phy@1 {
            reg = <1>;
            compatible = "ethernet-phy-ieee802.3-c22";
            max-speed = <1000>;
            reset-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>;
            reset-assert-us = <10000>;
            reset-deassert-us = <20000>;
        };
    };
};
常见陷阱: 很多工程师在移植内核时忘记在 mdio 节点中设置 #address-cells = <1> 和 #size-cells = <0>,导致 PHY 扫描失败,网络无法 link up。这是设备树语法错误中最容易忽略的问题之一。

1.4 设备树绑定流程:从 .dts 到驱动 probe

当内核启动并解析设备树后,网络设备的绑定遵循以下步骤:

  1. OF 核心解析:遍历 .dtb,为每个 compatible 匹配的节点创建 platform_device。
  2. MAC 驱动 probe:调用 stmmac_pltfr_probe(),读取 phy-mode、interrupts、reg 等属性。
  3. MDIO 总线注册:MAC 驱动解析子节点 mdio {},调用 of_mdiobus_register() 注册 MDIO 总线。
  4. PHY 扫描与绑定:MDIO 总线扫描 ethernet-phy@1 节点,读取 reg 地址,通过 phy_device_create() 创建 PHY 设备。
  5. PHY 驱动匹配:PHY 设备的 compatible 与 PHY 驱动列表匹配,调用 phy_probe(),完成初始化。
  6. 链路建立:MAC 驱动通过 phy_connect() 绑定 PHY,启动自动协商,最终建立网络链路。
关键洞察: 设备树中的 phy-mode(如 rgmii、rmii、sgmii)不仅影响 MAC 侧的接口时序配置,还决定了 PHY 驱动初始化时的延迟补偿策略。错误设置会导致丢包或无法 link up。

1.5 本章小结