做龙芯K上的VLLX驱动移植,不是那种把源码拿过来改个地址就完事的活。我们走马观碑组这次接到的任务,是把一套原本跑在其它硬件架构上的VLLX设备驱动完整挪到龙芯K平台上,让它能被系统正常枚举、申请中断、搬运数据,并且在长时间运行里不出怪问题。整个过程花了大概三周,中间踩了不少坑,也把很多“文档里不会写”的细节摸清楚了。如果你也准备在龙芯K这类平台上做类似外设驱动的迁移,或者只是想了解驱动跨架构移植到底要动哪些代码,这篇文章应该能帮你省下不少时间。
1. 龙芯K平台接盘VLLX驱动移植:先摸清外设是什么
1.1 拿到板子那天的现场情况
驱动移植这件事,最怕的不是代码难写,而是上来就动手。我们组第一天把板子通电,串口能进系统,内核版本、设备树都能看到,但VLLX对应的驱动模块根本没有可用的内核版本包。外设厂家给了一份能够在原平台上编译通过的驱动源码,目录结构倒挺完整,Makefile也写得像模像样,可真要交叉编译到龙芯K上就会发现,很多实现都是基于x86那套裸地址操作来做的。
所以我的第一个建议是,接到这种“驱动移植”任务时,首先整理三样东西:
- 目标板卡的系统环境:龙芯K内核版本、设备树源文件、是否启用了PCIe或平台设备框架。
- VLLX外设的硬件接口定义:它到底挂在什么总线上、寄存器基地址从哪里来、中断号怎么分配。
- 原有驱动源码的依赖清单:驱动里除了标准内核API,是否有厂商私有的库、是否有依赖特定CPU架构的汇编代码。
如果这三样拿不齐,后面每一步都会像踩在棉花上。
1.2 VLLX到底是哪种外设
先说清楚“VLLX”这个称呼。其实它是我们组内部对这个设备驱动的代号,主要是方便口头沟通,原文全称太长,而且在不同的项目里大家叫法不完全一致,所以我后面统一叫它VLLX。
从驱动开发角度,需要先判断它属于哪种设备模型:
第一种是PCIe设备。如果VLLX是一块PCIe板卡,在龙芯K系统里大概率能被lspci -nn识别出来,那驱动框架继续用struct pci_driver就行,改动重点是总线访问函数和DMA映射部分。
第二种是平台设备。很多龙芯K开发板上的外设并不走PCIe,而是直接挂在CPU的局部总线上,通过设备树描述地址和中断。VLLX如果属于这种,就需要把驱动从pci_driver改成platform_driver,并且用device_node里的compatible字段去匹配。
第三种是像FPGA逻辑扩展出来的自定义设备。这种最麻烦,它在Linux里没有现成的总线模型,常常是通过自定义IO窗口或寄存器桥映射到内存空间里。VLLX原始驱动里如果大量出现“直接写死物理地址”的代码,多半就是这种情况。
判断方法也很简单:进系统后先看/proc/iomem,确认有没有VLLX相关的地址区间;再看设备树文件里面有没有它的节点;最后看原驱动模块加载时靠什么函数完成设备注册。这三个信息能排除掉绝大多数不确定性。
1.3 移植工作量的真实分布
很多人以为驱动移植就是把代码里某个#include换掉,再把编译工具链换一换。实际上你把源码放进龙芯K的内核树里编第一次就会发现,报错的地方远不止这些。
以我个人经验,工作量大致是:
- 设备模型适配,大约占30%。这一步解决“驱动怎么被系统找到、probe什么时候执行”的问题。
- 寄存器访问和内存屏障修正,大约占20%。原驱动里可能大量使用
__raw_readl、ioread32等函数,甚至直接*(volatile u32 *)addr,这些在龙芯K上并非完全不能用,但正确性很依赖平台内存模型。 - DMA一致性与缓存同步修正,大约占30%。这是最隐蔽的部分,代码往往能编过,运行到传输大数据时才会随机丢数据或死锁。
- 中断处理和并发控制,大约占15%。
- 编译选项与内核配置对齐,大约是5%,但处理起来很烦。
想明白这个分布之后,我们就决定不直接改原驱动,而是先在龙芯K上搭好一套可以验证的最小环境,再一步一步把小模块换成真正驱动内容。这个顺序在后面帮了大忙。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 搭建龙芯K交叉编译环境,先编译一个最小驱动模块
2.1 工具链选择与交叉编译参数
龙芯K平台的CPU采用LoongArch指令集,交叉编译器并不是随便拿一个ARM或者x86工具链就能用的。建议直接用开发板配套的SDK工具链,或者从内核源码里看arch/loongarch/Makefile中推荐的交叉编译前缀。通常前缀是loongarch64-linux-gnu-,但不同版本可能有差异,所以最稳的方法是先检查工具链本身。
在SDK环境里执行:
bash复制source /opt/loongson-sdk/environment-setup-loongarch64
echo $CC
$CC -v
如果Target一栏里能看到类似loongarch64-unknown-linux-gnu或者loongarch64-linux-gnu字样,那这条工具链大概率是对的。后面编译内核模块时,我们不再依赖环境变量猜来猜去,直接把参数写进Makefile外部传参即可。
我用的编译命令一般是:
bash复制export ARCH=loongarch
export CROSS_COMPILE=loongarch64-linux-gnu-
make -C /path/to/loongson-kernel M=$(pwd) modules
这里-C后面必须是龙芯K目标机上同一版本的内核源码目录,而不是随便一个Linu
