3. MAC节点基础:ethernet节点必备属性

在设备树中,一个完整的 MAC(Media Access Control) 节点是网络设备驱动的起点。它描述了CPU或SoC内部以太网控制器的硬件连接方式、中断资源、总线地址以及外部PHY接口类型。本章将逐一拆解 compatible、reg、interrupts 和 phy-mode 这四个必备属性,并给出典型设备树片段与对应的驱动解析逻辑。

学习提示: 这四个属性是设备树编译器(DTC)和内核OF(Open Firmware)核心层强制检查的字段。缺少任何一个,驱动都可能无法正确 probe 或申请资源。

3.1 compatible —— 驱动匹配的“身份证”

compatible 属性是设备树中最关键的字符串列表,它告诉内核该设备与哪个驱动绑定。对于以太网MAC节点,其格式通常为:

compatible = "vendor,soc-ip-version", "vendor,soc-ip";

内核通过 of_match_table 进行精确匹配。以下是一个实际案例:

/* 设备树片段 */
ethernet@ffc00000 {
    compatible = "fsl,imx6q-fec", "fsl,imx6q-enet";
    reg = <0x0 0xffc00000 0x0 0x4000>;
    interrupts = <0 114 4>;
    phy-mode = "rgmii";
    ...
};

驱动侧匹配表:

static const struct of_device_id fec_of_match[] = {
    { .compatible = "fsl,imx6q-fec", .data = &fec_imx6q_data },
    { .compatible = "fsl,imx6q-enet", .data = &fec_imx6q_data },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_of_match);
匹配优先级: 内核优先使用列表中的第一个字符串进行精确匹配。如果第一个不匹配,则依次尝试后续字符串。建议将最具体的版本号放在最前面。

3.2 reg —— 寄存器地址与长度

reg 属性定义了MAC控制器的 物理基地址 和 地址范围。对于32位系统,格式为 <基地址 长度>;对于64位系统,使用两个32位单元表示一个64位地址:

/* 32位系统 */
reg = <0xffc00000 0x4000>;

/* 64位系统 */
reg = <0x0 0xffc00000 0x0 0x4000>;

驱动通过 of_iomap() 或 platform_get_resource() 获取该区域:

struct resource *res;
void __iomem *base;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
    return PTR_ERR(base);
字段 含义 典型值
基地址 MAC控制器的物理起始地址 0xffc00000
长度 寄存器映射的字节范围 0x4000 (16KB)
#address-cells 父节点定义的地址单元数 1 或 2
#size-cells 父节点定义的长度单元数 1 或 2
常见错误: 如果 reg 中的地址长度与父节点的 #address-cells / #size-cells 不匹配,内核将无法正确解析资源,导致 probe 失败。务必检查总线节点的 cell 定义。

3.3 interrupts —— 中断资源声明

interrupts 属性定义了MAC设备使用的中断号、触发类型和中断控制器信息。标准格式为:

interrupts = <中断类型 中断号 触发标志>;

对于ARM GIC(Generic Interrupt Controller),中断类型 0 表示SPI(共享外设中断),1 表示PPI(私有外设中断)。触发标志 4 表示上升沿触发,8 表示电平触发。

/* 设备树:SPI中断,中断号114,上升沿触发 */
interrupts = <0 114 4>;

/* 设备树:带中断父节点指定 */
interrupt-parent = <&gic>;
interrupts = <0 114 4>;

驱动获取中断号的标准方式:

int irq;

irq = platform_get_irq(pdev, 0);
if (irq < 0)
    return irq;

ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt,
                       0, "fec", ndev);
多中断场景: 部分MAC控制器支持多个中断(如发送完成、接收完成、错误中断)。此时 interrupts 属性可以包含多个条目,驱动通过 platform_get_irq(pdev, index) 按索引获取。

3.4 phy-mode —— 与PHY的接口协议

phy-mode 属性定义了MAC与外部PHY芯片之间的 MII(Media Independent Interface) 协议类型。这是驱动配置MAC内部接口逻辑的关键依据。

常见取值及含义:

phy-mode 值 接口类型 数据位宽 时钟频率
mii 标准MII 4位 25MHz / 2.5MHz
rmii 简化MII 2位 50MHz
rgmii 千兆MII 4位 125MHz
rgmii-id RGMII带内部延迟 4位 125MHz
sgmii 串行千兆MII 串行 1.25Gbps
rgmii-txid RGMII仅TX延迟 4位 125MHz
rgmii-rxid RGMII仅RX延迟 4位 125MHz

驱动解析示例:

const char *phy_mode_str;
int phy_mode;

phy_mode_str = of_get_property(np, "phy-mode", NULL);
if (!phy_mode_str)
    phy_mode_str = "mii";  /* 默认值 */

phy_mode = phy_interface_mode(phy_mode_str);
if (phy_mode < 0) {
    dev_err(dev, "invalid phy-mode: %s\n", phy_mode_str);
    return -EINVAL;
}

/* 根据phy_mode配置MAC内部接口逻辑 */
switch (phy_mode) {
case PHY_INTERFACE_MODE_RGMII:
    /* 配置RGMII时序 */
    break;
case PHY_INTERFACE_MODE_RMII:
    /* 配置RMII时钟 */
    break;
default:
    break;
}
时序陷阱: rgmii 与 rgmii-id 的区别在于是否由MAC内部插入TX/RX延迟。如果板级走线长度不匹配,选错模式会导致链路无法协商或大量CRC错误。建议在硬件设计阶段与PCB工程师确认延迟策略。

3.5 完整MAC节点示例与SVG结构图

下面是一个完整的MAC节点示例,集成了上述四个必备属性:

&fec1 {
    compatible = "fsl,imx6q-fec", "fsl,imx6q-enet";
    reg = <0x0 0xffc00000 0x0 0x4000>;
    interrupts = <0 114 4>;
    phy-mode = "rgmii";
    phy-handle = <&phy0>;
    status = "okay";

    mdio {
        #address-cells = <1>;
        #size-cells = <0>;

        phy0: ethernet-phy@0 {
            compatible = "ethernet-phy-ieee802.3-c22";
            reg = <0>;
        };
    };
};

下图展示了MAC节点与四个必备属性、PHY子节点之间的结构关系:

MAC节点必备属性结构图 ethernet@ffc00000 compatible reg interrupts phy-mode 驱动匹配标识 "fsl,imx6q-fec" "fsl,imx6q-enet" 寄存器基地址 0xffc00000 长度 0x4000 中断资源 SPI 114 上升沿触发 PHY接口协议 rgmii 千兆MII mdio 子节点 phy0: ethernet-phy@0

3.6 属性校验与常见错误排查

内核在 drivers/of/base.c 中提供了 of_device_is_available() 和 of_property_read_* 系列函数进行属性校验。以下是一个驱动probe阶段的属性检查流程:

  1. 检查节点状态: of_device_is_available(np) 确保 status = "okay"。
  2. 读取 compatible: of_match_node() 自动完成,失败则返回 -ENODEV。
  3. 获取 reg 资源: platform_get_resource(pdev, IORESOURCE_MEM, 0),失败返回 -ENXIO。
  4. 获取中断: platform_get_irq(pdev, 0),失败返回 -ENXIO。
  5. 解析 phy-mode: of_get_property(np, "phy-mode", NULL),缺失时使用默认值。
调试技巧: 在 /sys/firmware/devicetree/base/ 路径下可以查看实际加载的设备树属性。使用 dtc -I fs -O dts /sys/firmware/devicetree/base 可以反编译当前设备树,快速验证属性是否正确。