1. 网络设备驱动概述:Linux网络子系统架构、驱动分层模型、MAC与PHY角色分工
Linux 网络设备驱动是操作系统与物理网络硬件之间的核心桥梁。理解其整体架构、分层模型以及 MAC(媒体访问控制器)与 PHY(物理层收发器)的职责划分,是开发高性能网络驱动的第一步。本章从宏观到微观,系统梳理这些基础概念。
1.1 Linux 网络子系统整体架构
Linux 网络子系统采用分层的软件架构设计,从上至下依次为:系统调用接口、协议无关层、网络协议栈、设备无关接口、网络设备驱动,以及物理硬件。这种分层设计使得上层协议与底层硬件解耦,驱动开发者只需关注与硬件直接交互的层。
核心分层(自上而下):
- 系统调用接口:为用户空间提供 socket、bind、send、recv 等 API。
- 协议无关层:实现通用 socket 操作,如 inet_create、sock_alloc。
- 网络协议栈:包含 TCP、UDP、IP、ICMP、ARP 等核心协议实现。
- 设备无关接口:通过
struct net_device抽象所有网络设备,提供统一操作集。 - 网络设备驱动:直接操作硬件寄存器,处理中断、DMA 传输、MAC 配置。
- 物理硬件:MAC 控制器、DMA 引擎、PHY 芯片、SerDes 等。
1.2 驱动分层模型:从 net_device 到硬件寄存器
Linux 网络设备驱动遵循严格的软件分层模型。核心数据结构 struct net_device 代表一个抽象的网络设备,驱动通过注册该结构体与内核网络子系统交互。驱动层内部又可细分为:
- 通用接口层:实现
net_device_ops回调,如ndo_open、ndo_stop、ndo_start_xmit。 - 硬件抽象层:封装 MAC 控制器寄存器操作、DMA 描述符管理、中断服务例程。
- PHY 管理子层:通过 MDIO/MDC 总线与 PHY 芯片通信,处理链路状态、速率、双工模式。
关键设计原则:驱动应尽量复用内核提供的通用框架,如 PHY 子系统(phylib)、DMA 引擎 API、NAPI 轮询机制,避免直接操作硬件寄存器带来的平台耦合。
1.3 MAC 与 PHY 的角色分工
在以太网硬件架构中,MAC(Media Access Controller)和 PHY(Physical Layer Transceiver)是两个功能截然不同的组件。理解它们的职责边界,对于正确配置驱动和调试链路问题至关重要。
| 功能维度 | MAC 控制器 | PHY 芯片 |
|---|---|---|
| OSI 层 | 数据链路层 (L2) | 物理层 (L1) |
| 核心职责 | 帧封装/解封装、地址过滤、流控、CRC 校验 | 信号编码/解码、时钟恢复、线路驱动、链路检测 |
| 接口总线 | 与系统总线(AXI/PCIe)和 DMA 引擎交互 | 通过 MDIO/MDC 管理接口与 MAC 通信 |
| 速率协商 | 根据 PHY 上报结果配置自身 FIFO 和时钟 | 负责与对端 PHY 进行 Auto-Negotiation |
| 寄存器空间 | 厂商自定义寄存器(如 DMA 控制、中断掩码) | 标准 IEEE 802.3 寄存器(如 BMSR、BMCR) |
| 驱动代码 | 通常由 SoC 厂商提供,需适配具体平台 | 可使用内核通用 PHY 驱动或厂商专用驱动 |
常见误区:初学者常将 MAC 和 PHY 视为一个整体。实际上,MAC 负责数据帧的逻辑处理,PHY 负责物理信号的收发。驱动开发中,MAC 驱动需要主动通过 MDIO 读取 PHY 的状态寄存器,才能正确配置链路参数。
1.4 驱动开发中的关键数据结构
在编写网络设备驱动时,以下内核数据结构是必须掌握的:
struct net_device:网络设备的核心抽象,包含设备名称、MAC 地址、MTU、操作函数集等。struct net_device_ops:定义驱动需要实现的回调函数,如ndo_open、ndo_stop、ndo_start_xmit、ndo_set_rx_mode。struct sk_buff:套接字缓冲区,是网络数据在内核中传递的基本单元。struct napi_struct:NAPI 轮询机制的核心结构,用于减少中断频率,提升高吞吐量下的性能。struct phy_device:PHY 设备抽象,通过 phylib 框架管理链路协商和状态。
驱动注册流程(简化):
// 1. 分配 net_device 结构体
struct net_device *ndev = alloc_etherdev(sizeof(struct my_priv));
// 2. 设置 net_device_ops
ndev->netdev_ops = &my_netdev_ops;
// 3. 设置 MAC 地址(从设备树或 EEPROM 读取)
eth_hw_addr_set(ndev, mac_addr);
// 4. 注册网络设备
register_netdev(ndev);
// 5. 初始化 PHY(通过 phy_connect 或 of_phy_connect)
phydev = phy_connect(ndev, phy_node, my_adjust_link, 0, PHY_INTERFACE_MODE_RGMII);
1.5 小结与驱动开发视角
本章从 Linux 网络子系统整体架构出发,逐步深入到驱动分层模型,最后明确了 MAC 与 PHY 的职责边界。对于驱动开发者而言,核心要点如下:
- 网络驱动工作在内核的设备无关接口层之下,直接与硬件寄存器打交道。
- MAC 控制器负责数据帧的逻辑处理,PHY 负责物理信号收发,两者通过 MDIO 管理通道交互。
- 驱动开发应优先复用内核框架(phylib、NAPI、DMA API),减少重复造轮子。
- 理解
struct net_device、net_device_ops、sk_buff等核心数据结构,是编写正确驱动的基石。
实践建议:在开始编写驱动代码前,先阅读 SoC 数据手册中 MAC 控制器和 DMA 引擎的寄存器描述,以及 PHY 芯片的 IEEE 802.3 标准寄存器定义。这能帮助你快速定位硬件初始化、中断处理和链路管理中的问题。