3. 网卡硬件架构概览:MAC层、PHY层、DMA引擎、描述符环

在编写网卡驱动之前,必须理解硬件内部的数据流动路径。现代网卡(NIC)并非一个简单的“插网线就能收发”的黑盒,而是由多个专用硬件模块组成的协同系统。本章从驱动开发者的视角,拆解MAC、PHY、DMA引擎和描述符环(Descriptor Ring)这四大核心模块的职责与交互方式。

核心观点: 驱动代码不直接操作网线上的模拟信号,也不直接搬运每个字节。驱动通过描述符环与DMA引擎协作,让硬件自主完成数据搬运,CPU只在必要时处理控制面和异常。

3.1 网卡硬件分层模型

从OSI模型映射到硬件芯片,网卡内部可划分为三个主要层次:

  • PHY层(物理层):负责模拟信号的编码/解码、时钟恢复、线路协商(如10/100/1000Mbps自适应)。
  • MAC层(介质访问控制层):负责成帧、CRC校验、地址过滤、冲突检测(半双工)或流量控制(全双工)。
  • DMA引擎与描述符环:负责在MAC层和主机内存之间高速搬运数据包,无需CPU逐字节干预。

下图展示了数据包从网线到达主机内存的完整硬件路径:

网卡硬件数据流路径(接收方向) 网线 PHY层 MAC层 DMA引擎 主机内存 描述符环(Descriptor Ring) 位于主机内存,由驱动分配 说明:数据从网线进入PHY → MAC解帧 → DMA引擎通过描述符环将数据直接写入主机内存,CPU仅需处理描述符环的完成状态。

3.2 PHY层:模拟世界的守门员

PHY(Physical Layer)是网卡与物理介质的接口。驱动开发者通常不直接控制PHY的模拟电路,但需要通过MDIO/MDC总线(Management Data Input/Output)读写PHY寄存器,完成以下任务:

功能 说明 驱动关注点
链路检测 检测网线是否插入、对端是否协商成功 轮询PHY状态寄存器,触发中断或定时器
速率/双工协商 自动协商10/100/1000Mbps、全双工/半双工 读取协商结果,配置MAC层匹配
信号编码 将数字比特流编码为模拟信号(如MLT-3、PAM5) 无需干预,硬件自动完成
中断上报 链路状态变化时向MAC/主机发送中断 注册中断处理函数,更新网络设备状态
驱动提示: 多数通用网卡(如Intel I210、Realtek RTL8169)的PHY寄存器布局遵循IEEE 802.3标准。驱动初始化时,应读取PHY ID寄存器确认PHY型号,再执行特定初始化序列。

3.3 MAC层:数据帧的加工厂

MAC(Media Access Control)层负责处理完整的以太网帧。从驱动角度看,MAC层提供以下关键能力:

  • 帧封装/解封装:添加/移除前导码、帧起始定界符(SFD)、CRC校验码。
  • 地址过滤:根据MAC地址表决定是否接收帧(单播、多播、广播、混杂模式)。
  • 流量控制:支持暂停帧(Pause Frame)实现链路层流控。
  • 统计计数器:记录收/发帧数、CRC错误、冲突次数等。

MAC层通过内部总线(如PCIe、AXI)与DMA引擎连接。驱动通过MMIO(Memory-Mapped I/O)读写MAC控制寄存器,配置MAC地址、帧过滤规则、中断使能等。

MAC层内部功能模块 接收帧解析 地址过滤 CRC校验 帧封装 CRC生成 帧间距控制 MAC控制寄存器组

3.4 DMA引擎:数据搬运的核心

DMA(Direct Memory Access)引擎是网卡中最重要的性能模块。它负责在不占用CPU的情况下,将接收到的数据包从MAC层FIFO搬运到主机内存中的预分配缓冲区,或将待发送数据从主机内存搬运到MAC层FIFO。

DMA引擎的关键特性:

特性 描述 对驱动的影响
总线主控 DMA引擎作为PCIe主设备发起读写事务 驱动需分配物理连续内存或使用IOMMU映射
描述符驱动 DMA引擎通过读取描述符环获取传输参数 驱动必须正确初始化描述符环并通知硬件
中断聚合 可配置每N个包或每T微秒产生一次中断 减少CPU中断负载,但增加延迟
校验和卸载 硬件自动计算/校验IP/TCP/UDP校验和 驱动需在描述符中标记卸载标志
常见陷阱: DMA引擎操作的是物理地址,而非虚拟地址。驱动在分配DMA缓冲区时,必须使用一致性DMA API(如dma_alloc_coherent)或流式DMA映射(如dma_map_single),并确保缓冲区在DMA操作期间不被CPU缓存污染。

3.5 描述符环(Descriptor Ring):驱动与硬件的契约

描述符环是驱动与DMA引擎之间共享的环形数据结构,位于主机内存中。每个描述符(Descriptor)描述一个数据包缓冲区的位置、长度、状态和控制信息。描述符环是驱动与硬件通信的核心通道。

3.5.1 描述符结构

一个典型的接收描述符包含以下字段(以Intel I210为例):

struct rx_desc {
    __le64 addr;       // 缓冲区物理地址(64位)
    __le16 length;     // 接收到的数据长度(由硬件写入)
    __le16 csum;       // 校验和状态
    __le8  status;     // 完成状态(DD位:描述符完成)
    __le8  errors;     // 错误标志
    __le16 special;    // VLAN/哈希等信息
} __attribute__((packed));

发送描述符类似,但包含命令字段(如插入校验和、报告完成等)和数据长度(由驱动写入)。

3.5.2 环的工作原理

描述符环是一个循环队列,驱动和硬件通过头指针(Head)和尾指针(Tail)协作:

  1. 驱动在环中填充空闲描述符,指向可用的DMA缓冲区,然后更新尾指针寄存器通知硬件。
  2. DMA引擎从尾指针位置开始读取描述符,执行DMA传输,完成后设置描述符的完成位(DD)。
  3. 驱动在中断处理或轮询中扫描描述符环,找到DD位为1的描述符,处理数据包,然后回收描述符供硬件重用。
描述符环(Descriptor Ring)协作模型 Desc 0 (空闲) Desc 1 (空闲) Desc 2 (硬件使用中) Desc 3 (已完成) Desc 4 (已完成) Desc 5 (空闲) Desc 6 (空闲) Desc 7 (空闲) Head (驱动写入) 指向Desc 2 Tail (硬件读取) 指向Desc 5 驱动在空闲描述符中填充缓冲区地址 → 更新Tail → 硬件读取描述符执行DMA → 硬件设置DD位 → 驱动扫描DD位处理完成包

3.6 各模块协同工作流程

以接收一个以太网帧为例,完整流程如下:

步骤 执行者 操作
1 PHY 接收模拟信号,解码为数字比特流,恢复时钟
2 MAC 检测帧起始,去除前导码和SFD,进行CRC校验
3 MAC 检查目的MAC地址是否匹配(或混杂模式),通过则送入FIFO
4 DMA引擎 从描述符环读取下一个空闲描述符,获取缓冲区物理地址
5 DMA引擎 通过PCIe总线将FIFO中的数据写入主机内存缓冲区
6 DMA引擎 更新描述符状态(写入长度、设置DD位),可选触发中断
7 驱动 在中断处理或NAPI轮询中扫描描述符环,处理数据包
8 驱动 将数据包上送网络协议栈,回收描述符供硬件重用
性能关键点: 步骤4-6完全由硬件自主完成,CPU仅在步骤7-8介入。描述符环的大小(通常256-4096个描述符)直接影响吞吐量和延迟:环越大,硬件可预取的描述符越多,但驱动扫描开销也越大。

3.7 本章小结

网卡硬件架构的核心是分层协作:PHY处理模拟信号,MAC处理数据帧,DMA引擎通过描述符环与主机内存交互。驱动开发者的主要战场在描述符环的管理和DMA缓冲区的分配/回收。理解这些硬件模块的角色和交互方式,是后续实现环形缓冲区驱动的基础。

模块 驱动交互方式 关键寄存器/数据结构
PHY MDIO/MDC总线读写PHY寄存器 PHY ID寄存器、链路状态寄存器
MAC MMIO读写MAC控制寄存器 MAC地址寄存器、帧过滤寄存器、中断寄存器
DMA引擎 通过描述符环间接控制 描述符基址寄存器、头/尾指针寄存器、中断聚合寄存器
描述符环 驱动分配并维护环形队列 描述符数组(主机内存)、DD位、缓冲区地址