课程导学与环境准备:网卡驱动移植概述
各位同学,大家好。我是你们这门课的主讲。
做嵌入式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
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)
内核源码树准备
网卡驱动是内核的一部分,所以你得先有一份完整的内核源码树。我个人习惯用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 | 设备树网络辅助函数,必须开启 |
编译内核与设备树
# 编译内核
make -j4 uImage LOADADDR=0xC2000000
# 编译设备树
make stm32mp157d-atk.dtb
# 编译内核模块
make modules
# 安装模块到NFS根文件系统
make modules_install INSTALL_MOD_PATH=/home/user/nfsroot
编译完成后,你会得到arch/arm/boot/uImage和arch/arm/boot/dts/stm32mp157d-atk.dtb。把它们拷贝到TFTP目录,板子就可以通过网络启动了。
本章知识体系总览
为了让你对本章内容有个整体把握,我画了一张图。它展示了网卡驱动移植的完整知识链条:
这张图把网卡驱动移植的整个流程串起来了。你会发现,它不是一个线性的过程,而是一个循环迭代的过程——你可能会在设备树配置和驱动框架之间反复调试,直到网卡正常工作。
好了,环境准备就绪,内核源码树也搭好了。下一节,我们就要真正进入网卡驱动的核心——设备树解析与MAC驱动初始化。到时候,我会带你一行一行地看代码,把DesignWare MAC驱动的probe函数拆开揉碎了讲。