3. MAC节点基础:ethernet节点必备属性
在设备树中,一个完整的 MAC(Media Access Control) 节点是网络设备驱动的起点。它描述了CPU或SoC内部以太网控制器的硬件连接方式、中断资源、总线地址以及外部PHY接口类型。本章将逐一拆解 compatible、reg、interrupts 和 phy-mode 这四个必备属性,并给出典型设备树片段与对应的驱动解析逻辑。
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);
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子节点之间的结构关系:
3.6 属性校验与常见错误排查
内核在 drivers/of/base.c 中提供了 of_device_is_available() 和 of_property_read_* 系列函数进行属性校验。以下是一个驱动probe阶段的属性检查流程:
- 检查节点状态:
of_device_is_available(np)确保status = "okay"。 - 读取 compatible:
of_match_node()自动完成,失败则返回-ENODEV。 - 获取 reg 资源:
platform_get_resource(pdev, IORESOURCE_MEM, 0),失败返回-ENXIO。 - 获取中断:
platform_get_irq(pdev, 0),失败返回-ENXIO。 - 解析 phy-mode:
of_get_property(np, "phy-mode", NULL),缺失时使用默认值。
/sys/firmware/devicetree/base/ 路径下可以查看实际加载的设备树属性。使用 dtc -I fs -O dts /sys/firmware/devicetree/base 可以反编译当前设备树,快速验证属性是否正确。