Linux内核网络驱动设备树解析与中断绑定实战工程 - 第1节
1. 课程导论与预备知识
Linux 内核网络驱动是操作系统与物理网络设备之间的桥梁,负责数据包的收发、链路状态管理以及硬件控制。理解网络驱动的整体架构,是后续解析设备树与中断绑定的基础。
1.1.1 网络驱动在协议栈中的位置
Linux 网络协议栈自顶向下分为:系统调用接口 → 套接字层 → 传输层(TCP/UDP) → 网络层(IP) → 数据链路层 → 网络设备驱动 → 物理硬件。网络驱动位于数据链路层与物理硬件之间,直接操作硬件寄存器、描述符环和中断控制器。
关键认知: 网络驱动不处理 TCP 重传或 IP 路由,它的核心职责是:
(1) 初始化硬件并注册 net_device 结构体;
(2) 实现 open/stop/start_xmit 等操作函数;
(3) 处理硬件中断并上送数据包到协议栈。
(1) 初始化硬件并注册 net_device 结构体;
(2) 实现 open/stop/start_xmit 等操作函数;
(3) 处理硬件中断并上送数据包到协议栈。
1.1.2 网络驱动的核心数据结构
| 数据结构 | 所在文件 | 核心作用 |
|---|---|---|
struct net_device |
include/linux/netdevice.h | 网络设备的抽象,包含设备名、MAC 地址、操作函数集、统计信息等 |
struct net_device_ops |
include/linux/netdevice.h | 驱动必须实现的回调函数:ndo_open、ndo_stop、ndo_start_xmit 等 |
struct sk_buff |
include/linux/skbuff.h | 套接字缓冲区,承载网络数据包在内核各层之间传递 |
struct napi_struct |
include/linux/netdevice.h | NAPI 轮询机制的核心结构,用于减少中断频率、提升吞吐 |
1.1.3 网络驱动的注册与生命周期
- 模块加载:调用
platform_driver_register()或pci_register_driver()注册驱动。 - 探测阶段:probe 函数被调用,解析设备树获取资源,分配 net_device,设置操作函数,注册网络设备。
- 打开设备:用户执行
ifconfig eth0 up触发 ndo_open,申请 DMA 缓冲区、注册中断、启动 NAPI。 - 数据收发:ndo_start_xmit 发送数据包;硬件中断或 NAPI 轮询接收数据包。
- 关闭设备:ndo_stop 停止队列、释放中断、回收缓冲区。
- 模块卸载:remove 函数释放所有资源,注销网络设备。
1.2 设备树(DT)在驱动中的作用
设备树是一种描述硬件资源的数据结构,以树状节点形式向内核传递:寄存器地址、中断号、时钟频率、GPIO 引脚、DMA 通道等平台信息。在 ARM/ARM64/RISC-V 等非 x86 架构中,设备树是驱动获取硬件配置的主要途径。
1.2.1 设备树的核心语法
/dts-v1/;
/ {
model = "Embedded Network Board";
compatible = "vendor,board-version";
soc {
#address-cells = <1>;
#size-cells = <1>;
eth0: ethernet@10000000 {
compatible = "vendor,eth-driver";
reg = <0x10000000 0x1000>;
interrupts = <0 33 4>;
interrupt-parent = <&gic>;
phy-mode = "rgmii";
local-mac-address = [00 11 22 33 44 55];
};
};
};
| 属性 | 含义 | 驱动中对应 API |
|---|---|---|
compatible |
驱动匹配字符串,用于 of_match_table 匹配 | of_match_node() |
reg |
寄存器基地址与长度 | platform_get_resource() |
interrupts |
中断号、触发类型(高电平、上升沿等) | platform_get_irq() |
interrupt-parent |
中断控制器 phandle | irq_of_parse_and_map() |
phy-mode |
PHY 接口模式(MII/RMII/RGMII) | of_get_phy_mode() |
1.2.2 设备树与驱动绑定的流程
- 内核启动时解析 DTB(设备树二进制),构建
device_node树。 - 总线驱动(如 platform bus)扫描设备树节点,创建
platform_device。 - 驱动注册时,内核将
of_match_table中的 compatible 与设备树节点匹配。 - 匹配成功后调用驱动的
probe函数,传入platform_device指针。 - probe 函数通过
device_node读取 reg、interrupts 等属性,完成硬件初始化。
实战要点: 在编写网络驱动时,务必在
of_match_table 中声明与设备树一致的 compatible 字符串。常见错误是 compatible 拼写不一致导致 probe 不被调用。
1.3 中断子系统基础概念
中断是硬件通知 CPU 有事件需要处理的机制。在网络驱动中,中断用于通知数据包到达、发送完成、链路状态变化等事件。Linux 中断子系统由 中断控制器、中断描述符、中断处理程序 和 下半部机制 组成。
1.3.1 中断类型与触发方式
| 类型 | 触发方式 | 设备树中编码 | 典型场景 |
|---|---|---|---|
| 电平触发 | 高电平 / 低电平 | IRQ_TYPE_LEVEL_HIGH (4) / IRQ_TYPE_LEVEL_LOW (8) | 共享中断、边沿敏感设备 |
| 边沿触发 | 上升沿 / 下降沿 | IRQ_TYPE_EDGE_RISING (1) / IRQ_TYPE_EDGE_FALLING (2) | 网络控制器中断、GPIO 按键 |
| 快速中断 | 不可屏蔽 | IRQ_TYPE_NONE (0) | 时钟中断、紧急事件 |
1.3.2 中断处理流程
- 硬件触发:外设拉高/拉低中断线,中断控制器向 CPU 发送 IRQ。
- CPU 响应:CPU 保存上下文,跳转到中断向量表,执行通用中断入口。
- 中断分发:内核根据中断号查找
irq_desc,调用注册的handle_irq函数。 - 上半部执行:在中断上下文中执行快速处理(如清除中断标志、调度 NAPI)。
- 下半部执行:通过 tasklet、workqueue 或 NAPI 轮询在软中断上下文中完成数据包处理。
中断上下文限制: 上半部中不能调用可能导致睡眠的函数(如 kmalloc(GFP_KERNEL)、mutex_lock)。网络驱动通常在上半部仅做最小处理,将数据包接收放到 NAPI 轮询中完成。
1.3.3 设备树中的中断绑定
设备树通过 interrupts 属性和 interrupt-parent 属性描述中断连接关系。中断控制器节点需要提供 #interrupt-cells 指定中断描述符的单元数。
// 中断控制器节点(GIC)
gic: interrupt-controller@10400000 {
compatible = "arm,cortex-a15-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x10400000 0x10000>;
};
// 网络设备节点引用 GIC
ethernet@10000000 {
compatible = "vendor,eth-driver";
reg = <0x10000000 0x1000>;
interrupt-parent = <&gic>;
interrupts = <0 33 4>; // 类型=SPI, 中断号=33, 触发=高电平
};
其中 interrupts = <0 33 4> 的含义:
- 第一个单元:中断类型(0=SPI 共享外设中断,1=PPI 私有外设中断)。
- 第二个单元:中断号(相对于中断控制器的偏移)。
- 第三个单元:触发标志(4=高电平触发)。
1.4 本章知识结构总结
| 知识模块 | 核心内容 | 与后续章节的关联 |
|---|---|---|
| 网络驱动概述 | net_device、net_device_ops、sk_buff、NAPI | 第 3 章实现具体驱动操作函数 |
| 设备树基础 | compatible、reg、interrupts、of_match_table | 第 4 章解析设备树获取 MAC/PHY 参数 |
| 中断子系统 | 中断类型、触发方式、上半部/下半部、设备树中断绑定 | 第 5 章注册中断与 NAPI 集成 |
学习路径提示: 本章是后续所有实战章节的基石。建议读者在开发板上实际导出设备树文件(
dtc -I fs -O dts /sys/firmware/devicetree/base),对照本节内容逐字段分析网络节点,加深理解。