YT6801 GMAC 驱动核心解析
这份代码是 YT6801 芯片的 GMAC(千兆以太网控制器)Linux 内核驱动,核心实现以太网数据的收发、硬件控制、调试诊断等功能。以下从执行流程、核心原理、调用结构三方面拆解,帮你快速掌握核心逻辑。
一、整体架构与核心文件分工
先明确代码文件夹中关键文件的角色,建立整体认知:
文件 核心作用
fuxi-gmac.h 驱动核心结构体、宏定义(如寄存器偏移、标志位)
fuxi-gmac-net.c 核心!网络数据收发(TX/RX)、NAPI 轮询、数据包处理
fuxi-gmac-ioctl.c IOCTL 控制接口(调试、EFUSE 读写、MAC 配置、环回测试等)
fuxi-gmac-hw.c 硬件底层操作(寄存器读写、MAC/PHY 硬件初始化)
fuxi-gmac-desc.c DMA 描述符(desc)操作(初始化、重置、映射 / 解映射)
fuxi-gmac-phy.c PHY 芯片交互(链路协商、状态检测)
fuxi-gmac-pci.c PCIe 总线适配(设备枚举、资源申请、中断注册)
fuxi-efuse.c/h EFUSE(一次性可编程存储)操作(MAC 地址、配置参数读写)
fuxi-os.h 跨系统适配结构体(如用户 / 内核数据交互结构)
二、核心执行流程
驱动的执行流程遵循 Linux 网络驱动标准框架,核心分为初始化、数据收发、控制 / 调试、中断处理四大阶段。
阶段 1:驱动初始化(入口在 pci_probe)
PCI 设备探测:fuxi-gmac-pci.c中fxgmac_pci_probe作为 PCI 驱动入口,完成:
申请 PCI 资源(IO 地址、中断);
初始化核心结构体fxgmac_pdata(设备私有数据,包含硬件操作集、通道、统计信息等);
注册网络设备(register_netdev);
初始化硬件(调用hw_ops->hw_init,对应fuxi-gmac-hw.c);
注册 NAPI(网络中断优化机制)、MSI-X 中断(多队列中断)。
硬件初始化:hw_ops(硬件操作集)完成:
复位 GMAC 控制器;
配置 MAC 参数(速率、双工、校验和卸载等);
初始化 DMA 收发描述符环(TX/RX Ring);
初始化 PHY(链路协商)。
阶段 2:数据接收(RX)流程(核心在fuxi-gmac-net.c)
Linux 网络驱动采用NAPI(中断 + 轮询) 优化高吞吐场景,RX 流程如下:
plaintext
硬件收包 → 触发RX中断 → 关闭中断 → NAPI轮询 → 处理数据包 → 重新使能中断
核心函数调用链:
plaintext
fxgmac_one_poll_rx(NAPI轮询入口)
↓
fxgmac_rx_poll(核心RX处理)
↓
fxgmac_dev_read(读取硬件接收状态)
↓
fxgmac_create_skb(创建skb数据包)
↓
napi_gro_receive(将skb交给内核协议栈)
关键逻辑:
描述符环(RX Ring):驱动预先分配一组 DMA 描述符,每个描述符指向一个 skb(内核网络数据包结构),硬件收包后直接 DMA 到 skb 缓冲区,避免 CPU 拷贝;
NAPI 轮询:中断触发后,先关闭中断,再通过fxgmac_rx_poll批量处理数据包(budget为单次最大处理数),处理完再开中断;
数据包校验:检查长度、校验和、VLAN 标签、错误标志,异常则统计并丢弃;
环回测试适配:代码中包含环回测试逻辑(fxgmac_test_tso_flag/fxgmac_test_packet_len),接收包后拷贝到测试缓冲区,用于调试。
阶段 3:数据发送(TX)流程(核心在fuxi-gmac-net.c)
TX 流程是 “内核提交数据包→驱动填充描述符→硬件 DMA 发送→轮询清理完成的描述符”:
plaintext
协议栈发包 → dev_queue_xmit → 驱动tx函数 → 填充TX描述符 → 硬件DMA发送 → NAPI轮询清理描述符
核心函数调用链:
plaintext
fxgmac_one_poll_tx(NAPI轮询入口)
↓
fxgmac_tx_poll(核心TX处理)
↓
hw_ops->tx_complete(检查硬件是否完成发送)
↓
desc_ops->unmap_desc_data(解映射skb,释放资源)
↓
netdev_tx_completed_queue(统计发送完成的包数/字节数)
关键逻辑:
TX 描述符环:与 RX 类似,驱动将协议栈的 skb 映射到 DMA 地址,填充描述符后通知硬件取包发送;
发送完成检查:fxgmac_tx_poll轮询检查描述符的 “OWN 位”(硬件所有权),硬件发送完成后,驱动释放 skb 并重置描述符;
TX 挂死检测:代码中包含 TX 挂死保护(FXGMAC_TX_HANG_TIMER_ENABLED),若描述符长时间未被硬件处理,触发设备重启;
队列唤醒:当 TX 描述符空闲数超过阈值(FXGMAC_TX_DESC_MIN_FREE),唤醒被暂停的发送队列。
阶段 4:IOCTL 控制与调试(核心在fuxi-gmac-ioctl.c)
用户层通过ioctl指令与驱动交互,完成调试、配置操作,核心流程:
plaintext
用户层调用ioctl → fxgmac_netdev_ops_ioctl(入口)
↓
校验指令合法性(魔数、指令号)
↓
拷贝用户层数据到内核
↓
根据cmd_type分支处理(如环回测试、EFUSE读写、MAC配置)
↓
将结果拷贝回用户层
核心指令类型(cmd_type):
指令类型 作用
FXGMAC_DFS_IOCTL_DIAG_BEGIN/END 环回测试开始 / 结束
FXGMAC_EFUSE_READ/WRITE_* EFUSE 读写(MAC 地址、补丁寄存器、LED 配置)
FXGMAC_GET/SET_MAC_DATA 读取 / 设置 MAC 地址(写入 EFUSE 永久生效)
FXGMAC_DFS_IOCTL_DEVICE_RESET 设备重置
FXGMAC_EFUSE_LOAD 加载 EFUSE 配置到硬件
三、核心原理
- DMA 描述符机制
GMAC 控制器通过DMA 描述符环实现无 CPU 参与的数据包收发:
描述符(fxgmac_dma_desc)包含缓冲区地址、长度、状态位(如 OWN 位:0 = 驱动拥有,1 = 硬件拥有);
TX:驱动填充描述符→置 OWN 位→硬件 DMA 取数发送→清 OWN 位→驱动回收;
RX:驱动预置空描述符→置 OWN 位→硬件收包后 DMA 填数据→清 OWN 位→驱动取数。 - NAPI 机制
传统中断模式下,高吞吐时中断频繁导致 CPU 占用过高;NAPI 将 “中断触发” 改为 “中断 + 轮询”:
首次收包触发中断,关闭中断,切换为轮询模式;
轮询处理完所有待处理包后,重新使能中断;
驱动中fxgmac_one_poll_rx/tx是 NAPI 轮询函数,绑定到中断队列。 - EFUSE(一次性可编程存储)
YT6801 的 EFUSE 用于存储关键配置(掉电不丢):
MAC 地址、PHY 配置、LED 参数、补丁寄存器;
fuxi-efuse.c提供读写接口,ioctl指令通过hw_ops调用这些接口;
写 EFUSE 通常是一次性操作,驱动中做了参数校验避免误写。 - 环回测试(调试核心)
驱动支持硬件环回测试(用于调试):
通过FXGMAC_DFS_IOCTL_DIAG_BEGIN开启测试,标记lb_test_flag=1;
收发流程中检测测试标志,将收到的包缓存到fxgmac_test_skb_array;
FXGMAC_DFS_IOCTL_DIAG_END关闭测试,释放缓存的 skb。
四、核心调用结构(关键结构体 + 函数依赖) - 核心结构体
结构体 作用 核心成员
fxgmac_pdata 设备私有数据(全局核心) netdev(网络设备)、hw_ops(硬件操作集)、channel(收发通道)、expansion(扩展字段:测试标志、skb 缓存)
fxgmac_channel 收发通道(多队列) tx_ring/rx_ring(描述符环)、napi_tx/napi_rx(NAPI 对象)
fxgmac_ring 描述符环 cur/dirty(读写指针)、dma_desc_count(描述符数量)、desc_data(描述符数据)
fxgmac_desc_data 描述符关联数据 dma_desc(硬件描述符)、skb(关联的数据包)、rx/tx(收发专用字段)
ext_ioctl_data IOCTL 数据交互 cmd_type(指令类型)、cmd_buf(数据大小) - 核心操作集(函数指针)
驱动通过 “操作集” 解耦硬件逻辑与上层流程,核心操作集:
c
运行
// 硬件操作集(fuxi-gmac-hw.c实现)
struct fxgmac_hw_ops {
int (*hw_init)(struct fxgmac_pdata *pdata); // 硬件初始化
bool (*tx_complete)(struct fxgmac_dma_desc *desc); // 检查TX完成
int (*read_mac_subsys_from_efuse)(…); // 读MAC地址
int (*write_mac_subsys_to_efuse)(…); // 写MAC地址
// … 其他硬件操作(LED、EFUSE、中断)
};
// 描述符操作集(fuxi-gmac-desc.c实现)
struct fxgmac_desc_ops {
void (*tx_desc_reset)(struct fxgmac_desc_data *desc); // 重置TX描述符
void (*unmap_desc_data)(…); // 解映射skb
// … 其他描述符操作
};
3. 关键函数调用关系图
plaintext
┌─────────────────────────────────┐
│ 上层内核网络栈 │
└───────────┬─────────────────────┘
│
▼
┌─────────────────────────────────┐
│ register_netdev (网络设备注册) │
└───────────┬─────────────────────┘
│
▼
┌─────────────────────────────────┐
│ NAPI轮询(rx/tx) │
│ ├─ fxgmac_one_poll_rx │
│ │ └─ fxgmac_rx_poll │
│ │ ├─ fxgmac_create_skb │
│ │ └─ napi_gro_receive │
│ └─ fxgmac_one_poll_tx │
│ └─ fxgmac_tx_poll │
│ ├─ hw_ops->tx_complete │
│ └─ desc_ops->unmap_desc │
└───────────┬─────────────────────┘
│
▼
┌─────────────────────────────────┐
│ 硬件操作(hw_ops) │
│ ├─ 寄存器读写 │
│ ├─ DMA描述符操作 │
│ └─ PHY/EFUSE交互 │
└───────────┬─────────────────────┘
│
▼
┌─────────────────────────────────┐
│ IOCTL控制(调试/配置) │
│ └─ fxgmac_netdev_ops_ioctl │
│ ├─ 环回测试控制 │
│ ├─ MAC地址配置 │
│ └─ EFUSE读写 │
└─────────────────────────────────┘
五、快速上手关键点
核心入口:
驱动加载:PCI probe(fxgmac_pci_probe)→ 硬件初始化 → 注册 netdev;
数据收发:NAPI 轮询(fxgmac_rx_poll/fxgmac_tx_poll)是核心;
调试配置:fxgmac_netdev_ops_ioctl是用户层控制入口。
关键调试点:
环回测试:通过FXGMAC_DFS_IOCTL_DIAG_BEGIN开启,抓包验证收发;
MAC 地址:FXGMAC_GET/SET_MAC_DATA读写 EFUSE 中的 MAC;
TX 挂死:关注FXGMAC_TX_HANG_TIMER_ENABLED相关逻辑,排查硬件卡死;
描述符环:ring->cur/ring->dirty指针是否正常推进(异常则收发异常)。
核心宏定义:
FXGMAC_MAX_DBG_BUF_LEN:调试缓冲区大小;
FXGMAC_TX_DESC_MIN_FREE:TX 队列唤醒阈值;
FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED:开启 PHY 环回检测;
FXGMAC_NOT_USE_PAGE_MAPPING:关闭页映射(影响 skb 创建方式)。
异常排查:
收不到包:检查 RX 描述符是否初始化、PHY 链路是否 UP、中断是否注册;
发不出包:检查 TX 描述符 OWN 位、硬件是否复位、队列是否暂停;
MAC 地址失效:检查 EFUSE 读写是否成功(FXGMAC_GET_MAC_DATA)。