课程导学与环境准备:网卡驱动移植概述

各位同学,大家好。我是你们这门课的主讲。

做嵌入式Linux开发这么多年,我有个很深的体会:网卡驱动移植,是嵌入式工程师从“能用”走向“精通”的一道分水岭。为什么这么说?你想想看,一个系统跑起来了,串口能打印,LED能闪烁,这只能算入门。但当你需要让设备联网、做数据采集、做远程控制的时候,网卡能不能稳定工作,就成了整个项目的命门。

我个人习惯把网卡驱动移植比作“给系统装上网线”。听起来简单,但实际做起来,从硬件管脚配置、总线枚举、驱动匹配,到中断处理、DMA传输、网络协议栈对接,每一个环节都可能让你卡上好几天。

这门课,就是要把这些“卡点”一个一个拆开,讲清楚。

课程目标:学完你能做什么?

我不喜欢讲虚的。这门课的目标非常明确,学完之后,你应该能独立完成以下工作:

  • 看懂芯片手册:拿到一款新的SoC或网卡芯片,能快速定位到MAC层、PHY层、MDIO接口的关键寄存器。
  • 移植标准驱动:把Linux内核里已有的网卡驱动(比如DesignWare、STM32、i.MX系列)适配到你的板子上。
  • 调试网络问题:网卡不工作、丢包、速率不对——能通过dmesg、ifconfig、ethtool、抓包等手段定位问题。
  • 验证网络功能:从ping通到TCP/UDP吞吐量测试,再到实际业务场景下的稳定性验证。

说白了,就是让你从“调通”到“调稳”。

开发板与交叉编译环境搭建

工欲善其事,必先利其器。环境搭建这一步,我建议你认真对待。我在项目中遇到过好几次,因为交叉编译工具链版本不对,导致驱动编译出来加载就崩溃的情况。嗯,这里要注意。

硬件平台选择

这门课我以STM32MP157开发板为例进行讲解。为什么选它?

  • 它集成了Cortex-A7和Cortex-M4双核,典型的嵌入式异构架构
  • 内置的DesignWare Ethernet MAC是业界非常通用的IP核,学会了它,换到其他平台(比如i.MX、Allwinner)思路完全一样
  • 资料丰富,社区活跃,踩坑成本低

当然,如果你手头是其他板子,也没关系。我会在课程中标注出不同平台的差异点。

交叉编译工具链安装

交叉编译,说白了就是在你的PC上编译出能在ARM开发板上运行的代码。我习惯用Linaro GCC,稳定且兼容性好。

# 下载ARM GCC交叉编译工具链
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

# 解压到指定目录
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/

# 配置环境变量(建议写入~/.bashrc)
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

# 验证安装
arm-linux-gnueabihf-gcc --version
小提示:我曾经因为忘记设置CROSS_COMPILE环境变量,直接用gcc编译内核模块,结果在板子上加载时报“Invalid module format”。这个坑,你千万别踩。每次打开新终端,记得检查一下环境变量是否生效。

TFTP/NFS网络启动环境

做驱动开发,频繁烧写SD卡或eMMC太慢了。我强烈建议你搭建TFTP + NFS网络启动环境。这样,你在PC上编译好内核和设备树,通过TFTP下载到板子;根文件系统通过NFS挂载,修改代码后直接重启验证,效率提升不止一个量级。

# 安装TFTP服务器(Ubuntu)
sudo apt-get install tftpd-hpa
sudo mkdir -p /tftpboot
sudo chmod 777 /tftpboot

# 配置TFTP(/etc/default/tftpd-hpa)
TFTP_DIRECTORY="/tftpboot"
TFTP_OPTIONS="-l -c -s"

# 安装NFS服务器
sudo apt-get install nfs-kernel-server
# 配置NFS导出(/etc/exports)
/home/user/nfsroot *(rw,sync,no_subtree_check,no_root_squash)
注意:NFS的no_root_squash选项要谨慎使用。它允许开发板以root权限访问你的PC文件系统,调试时很方便,但生产环境绝对不能这么配。我曾经在客户现场忘了改回来,被安全审计抓了个正着……

内核源码树准备

网卡驱动是内核的一部分,所以你得先有一份完整的内核源码树。我个人习惯用Linux内核主线版本,而不是SoC厂商提供的BSP内核。为什么?

  • 主线内核代码质量更高,社区review充分
  • 驱动框架更新及时,学习价值更大
  • 遇到问题更容易在社区找到答案

下载与配置内核

# 下载主线内核(以5.10 LTS为例)
git clone --depth=1 -b linux-5.10.y git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

# 进入源码目录
cd linux-stable

# 使用默认配置(以STM32MP1为例)
make stm32mp1_defconfig

# 手动配置网卡驱动相关选项
make menuconfig

在menuconfig中,你需要重点关注以下选项:

配置项 路径 说明
CONFIG_STMMAC_ETH Device Drivers → Network device support → Ethernet driver support → STMicroelectronics devices DesignWare MAC驱动,STM32MP1使用这个
CONFIG_PHYLIB Device Drivers → PHY Device support PHY层框架,必须开启
CONFIG_MICREL_PHY Device Drivers → PHY Device support → Micrel PHYs 如果你的板子用的是Micrel PHY(比如KSZ9031),选上
CONFIG_OF_NET Device Drivers → Network device support → OF helpers for network devices 设备树网络辅助函数,必须开启
核心要点:网卡驱动移植,本质上就是让内核的驱动框架和你的硬件设备“对上号”。这个“对上号”的过程,靠的就是设备树(Device Tree)。设备树告诉内核:你的网卡挂在哪条总线上、中断号是多少、PHY地址是什么、时钟频率是多少。所以,学会看设备树,是网卡驱动移植的第一步。

编译内核与设备树

# 编译内核
make -j4 uImage LOADADDR=0xC2000000

# 编译设备树
make stm32mp157d-atk.dtb

# 编译内核模块
make modules

# 安装模块到NFS根文件系统
make modules_install INSTALL_MOD_PATH=/home/user/nfsroot

编译完成后,你会得到arch/arm/boot/uImagearch/arm/boot/dts/stm32mp157d-atk.dtb。把它们拷贝到TFTP目录,板子就可以通过网络启动了。

避坑指南:我曾经在编译内核时用了错误的LOADADDR,导致内核解压后直接跑飞。后来养成习惯,每次编译前都去查一下对应SoC的启动地址。STM32MP1的A7核是从0xC2000000启动的,这个值写在芯片手册的“Boot ROM”章节里。

本章知识体系总览

为了让你对本章内容有个整体把握,我画了一张图。它展示了网卡驱动移植的完整知识链条:

网卡驱动移植知识体系 硬件基础 SoC手册 / 原理图 / 管脚复用 环境搭建 交叉编译链 / TFTP / NFS 内核源码树 主线内核 / 配置 / 编译 设备树配置 MAC节点 / PHY节点 / 时钟 / 中断 驱动框架 probe / 中断处理 / NAPI / DMA 网络功能验证 ping / iperf / ethtool / 抓包分析 从硬件到驱动,从编译到验证,环环相扣

这张图把网卡驱动移植的整个流程串起来了。你会发现,它不是一个线性的过程,而是一个循环迭代的过程——你可能会在设备树配置和驱动框架之间反复调试,直到网卡正常工作。

好了,环境准备就绪,内核源码树也搭好了。下一节,我们就要真正进入网卡驱动的核心——设备树解析与MAC驱动初始化。到时候,我会带你一行一行地看代码,把DesignWare MAC驱动的probe函数拆开揉碎了讲。


专注资料整理