昇腾310P(A300-3010)驱动移植与安装实战:在内核7.0上从编译失败到10卡全识别

一句话背景:华为 2022 年发布的 A300-3010(Ascend 310P)驱动源码面向 4.19/5.x 内核,在 Ubuntu 26.04 + 内核 7.0 上直接安装会因大量 API 变更而编译失败。本文完整记录了将驱动源码移植到内核 7.0 并完成官方安装的全过程。

最终成果:10 张 Ascend 310P 全部被 npu-smi 识别,Health 全 OK,驱动 23.0.0 + 固件 7.1.0.3.220 双向配套。

适用读者:需要在新内核上部署昇腾 NPU、或对内核驱动移植感兴趣的开发者。

目录


引言

为什么写这篇文章

昇腾(Ascend)系列 NPU 在国产 AI 算力中占有重要地位。然而,华为官方驱动的更新节奏往往滞后于 Linux 内核的演进——2022 年发布的 A300-3010 驱动 23.0.0 源码基于 4.19/5.x 内核编写,当它遇上 Ubuntu 26.04 自带的内核 7.0 时,会因为大量内核 API 的删除与变更而无法编译。

网上关于"昇腾驱动装不上"的帖子不少,但大多停留在"换个旧内核"的权宜之计。本文记录的是另一条路:不降级内核,而是把驱动源码移植到 7.0 上编过,并且仍然使用华为官方安装器完成 ko 落盘、依赖注册和环境配置。

环境速览

项目内容
操作系统Ubuntu 26.04 LTS
内核7.0.0-31-generic
编译器gcc 15
硬件10 × Huawei 19e5:d100(Ascend 310P),虚拟机直通
驱动包A300-3010-npu-driver_23.0.0_linux-x86_64.run
固件包A300-3010-npu-firmware_7.1.0.3.220.run

你将收获

读完本文,你将能够:

  1. 理解旧驱动源码在新内核上编译失败的三类根因;
  2. 掌握 30+ 处内核 API 迁移的具体做法(能力位、定时器、页表、GUP、MSI 等);
  3. 学会与官方安装器配合——把补丁替换进它的 payload,而非绕过它;
  4. 获得一份可直接复制执行的安装命令集(全为官方命令)和踩坑对照表。

第一部分 安装操作(官方流程)

本章的命令全部来自华为官方安装包与官方文档,可直接复制执行。

核心原则:不绕过官方安装器。驱动源码的移植改动在第二部分说明,本章只涉及如何把移植后的源码交给官方安装器执行。

一、环境准备

# 1) 官方文档要求的依赖(Debian/Ubuntu 系)
apt-get update
apt-get install -y dkms gcc make linux-headers-$(uname -r) pciutils net-tools

# 2) 官方要求的存在用户/属组
groupadd -f HwHiAiUser
useradd -g HwHiAiUser -d /home/HwHiAiUser -m HwHiAiUser -s /bin/bash 2>/dev/null || true

# 3) 确认物料齐全
ls -l /root/downloads/A300-3010-npu-driver_23.0.0_linux-x86_64.run
ls -l /root/downloads/A300-3010-npu-firmware_7.1.0.3.220.run

提示:若机器上还没有"已移植好的驱动源码",需要先恢复一份。源码本身就是驱动包内的 driver/kernel,移植改动见第九章。本机源码备份位于 /root/docs/davinci_hiai-1.0-patched.tar.gz

tar -xzf /root/docs/davinci_hiai-1.0-patched.tar.gz -C /usr/src

二、安装驱动内核模块

官方 .run 每次执行都会重新解包并覆盖驱动源码目录,而包内源码编不过内核 7.0,所以必须先解包、用移植后的源码替换包内源码、再执行官方安装脚本

# 1) 若之前有失败的安装,先把 /etc/ascend_install.info 去重
#    (下面这条输出 >1 才需要处理;详见踩坑记录 #3)
grep -c "^Driver_Install_Path_Param=" /etc/ascend_install.info 2>/dev/null
#    需要处理时执行:
#    cp /etc/ascend_install.info /etc/ascend_install.info.bak
#    awk -F= '!seen[$1]++' /etc/ascend_install.info > /tmp/ai && mv /tmp/ai /etc/ascend_install.info

# 2) 驱动包只解包、不执行
cd /root/downloads
./A300-3010-npu-driver_23.0.0_linux-x86_64.run --noexec --nox11 --extract=/tmp/drvpayload

# 3) 重装场景:先解除已装目录的"不可变"属性(首次安装可跳过)
chattr -iR /usr/local/Ascend/driver/kernel 2>/dev/null

# 4) 用移植后的源码覆盖包内源码(首次安装这一条就够了)
rsync -a /usr/src/davinci_hiai-1.0/ /tmp/drvpayload/driver/kernel/
# 重装场景再多同步一份到安装器取样目录:
[ -d /usr/local/Ascend/driver/kernel ] && rsync -a /usr/src/davinci_hiai-1.0/ /usr/local/Ascend/driver/kernel/

# 5) 执行官方安装脚本
#    install.sh 的前两个参数是 run 包名与包路径(脚本会截掉前两个字符得到绝对路径)
#    已装过会问 y/n,用管道自动回答
cd /tmp/drvpayload
printf 'y\ny\ny\n' | bash driver/script/install.sh "A300-3010-npu-driver_23.0.0_linux-x86_64.run" \
  ".//root/downloads" --full --install-for-all

成功标志:

[INFO]Driver package installed successfully! Reboot needed for installation/upgrade to take effect!

三、重启并确认驱动就绪

reboot          # 必须重启:驱动在此过程中向芯片下发镜像、把芯片拉起来

# 机器起来后(约 1-2 分钟)执行以下检查
lsmod | grep -cE "^(drv_|ascend_|dbl_)"        # 期望 20
npu-smi info                                   # 期望 10 张卡,Health 均为 OK
dmesg | grep -c "Set device boot finish"       # 期望 10(10 张芯片全部启动完成)
dkms status                                    # 期望 davinci_hiai/1.0, <内核>, x86_64: installed

四、升级固件并复验

固件工具要求芯片在线,所以必须在驱动就绪(上一步重启完成)之后再执行:

cd /root/downloads
./A300-3010-npu-firmware_7.1.0.3.220.run --full

# 成功标志:The firmware of [10] chips are successfully upgraded.
reboot          # 必须再重启一次,新固件才会在芯片上生效

# 最终复验
npu-smi info
/usr/local/Ascend/driver/tools/upgrade-tool --device_index -1 --system_version   # 0-9 号设备都应能读到版本
dmesg | grep -c "Set device boot finish"                                        # 10
grep -m1 '^Version=' /usr/local/Ascend/firmware/version.info                    # 7.1.0.3.220

完成判据npu-smi info 出现 10 张 310、Health 全 OKdkms statusinstalled;固件版本 7.1.0.3.220

五、常见报错对照表

屏幕上的关键词原因怎么做
Operation not permitted + mkstemp ... /usr/local/Ascend/driver/kernel/...安装器给已装文件加了"不可变"属性(chattr +i先执行 chattr -iR /usr/local/Ascend/driver/kernel 再覆盖
安装器长时间不动(>10 分钟无输出)已装过驱动时会问 [y/n],没有输入就卡住用管道喂答案:printf 'y\ny\ny\n' | bash driver/script/install.sh ...
Unrecognized parametersinstall.sh 少了前两个参数前两参必须是 (run 包名, ".//绝对路径"),见第二章第 5 步
install path /usr/local not exists/etc/ascend_install.info 被写重复了按 key 去重该文件(见第二章第 1 步)
None of the chips are up芯片还没启动(驱动没加载或需要复位)先整机 reboot;起来后 dmesg | grep -c "boot finish" 应为 10
Unknown symbol xxx(模块加载时报)驱动源码里还有新内核删掉的 API,属移植漏网见第九章;用编译验证命令复现并补掉该符号
Wait boot mode from bios time out在下发固件的过程中卸载了驱动,卡停在异常态reboot 整机复位即可恢复(不要在驱动加载/下发固件时 rmmod
Dkms install failed / There has no xxx.koDKMS 编译失败看编译日志 /var/lib/dkms/davinci_hiai/1.0/build/make.log 里第一条 error:
dcmi module initialize failed用户态库读不到驱动(模块没加载 / 芯片没起来)确认 lsmod | grep -c drv_ 非 0,且 dmesg | grep -c "boot finish" 等于卡数

三条通用规则

  1. 命令都要 root
  2. 安装动作会写 /usr/local/etc/lib/modules/usr/src,需在无沙箱/只读限制的环境执行;
  3. 每一步可重复执行,失败修好后直接重跑该步。

第二部分 原理与移植实录

六、环境与物料

项目内容
操作系统Ubuntu 26.04 LTS(resolute),apt 体系(无 yum/dnf)
内核7.0.0-31-generic/usr/src/linux-headers-7.0.0-31-generic
编译器gcc 15(/usr/lib/gcc/x86_64-linux-gnu/15
硬件10 × Huawei 19e5:d100(Ascend 310P),0000:00:0B.0 ~ 0000:00:14.0,虚拟机直通
驱动包A300-3010-npu-driver_23.0.0_linux-x86_64.run
固件包A300-3010-npu-firmware_7.1.0.3.220.run
驱动源码随驱动包发布,安装时释放到 /usr/src/davinci_hiai-1.0(2022 年代码,面向 4.19/5.x 内核)
用户/属组HwHiAiUser:HwHiAiUser(安装器强制要求)

七、问题分析

7.1 现象

安装器(.run --full --install-for-all)在 DKMS 阶段失败:

[ERROR]Dkms install failed, details in : /var/log/ascend_seclog/ascend_install.log
[ERROR]Driver_ko_install failed, details in : /var/log/ascend_seclog/ascend_install.log
[INFO]Failed to install driver package, please retry after uninstall and reboot!

make.log 显示的是"旧驱动源码 × 新内核 API"的典型冲突:fatal error: linux/genhd.h: No such filestatic assertion failed: "pointer type mismatch in container_of()"too many arguments to function 'get_user_pages_remote''PROFILE_TASK_EXIT' undeclared 等。

7.2 根因(三条)

  1. API 代差:驱动源码基于 4.19/5.x 编写,内核 7.0 删改了大量接口(能力位结构、del_timerfollow_pfnhrtimer_init 等)。
  2. 安装器会覆盖补丁源码:每次执行 .run 都会重新解包,cp -rf 覆盖 /usr/local/Ascend/driver/kernel/,再由 run_driver_dkms_install.sh 拷贝到 /usr/src/davinci_hiai-1.0在源码树里改完直接重跑安装器,补丁必被抹掉。
  3. 状态残留:多次失败安装把 /etc/ascend_install.info 写成重复键值块,安装器据此解析出"两条安装路径",直接报 install path ... not exists;此外在驱动向卡下发镜像的过程中卸载模块,会使卡停在异常态(探针报 Wait boot mode from bios time out)。

八、总体思路

整个排查与修复过程可以用下面这张流程图概括:

官方 .run 安装失败:
DKMS 编译不过

根因定位

驱动源码 vs 内核 7.0
API 代差

.run 每次覆盖
已打补丁的源码

install.info 被写重复
→ 路径误判

内核 API 移植
(30+ 处改动)

--noexec --extract 解包
→ 替换包内源码 → 跑 install.sh

按 key 去重 install.info

dkms build 全绿
22 个 ko / 0 undefined

官方安装器安装 ko
+ 落盘到 /lib/modules

重启:20 个模块自动加载

固件升级:10 张芯片

npu-smi:10 张 310 全部 OK

核心策略:先在源码树上把移植补丁编绿,再把补丁源码替换进官方安装包的 payload,最后仍由官方安装脚本完成 ko 落盘、依赖注册、环境配置——不绕过、不手工替代官方安装器的任何环节。

九、内核 API 移植改动清单

下表汇总了本次移植中处理的所有内核 API 变更:

类别内核 7.0 的变化移植做法涉及位置
能力位kernel_cap_t 变为单个 64 位标量,CAP_FOR_EACH_U32 删除CAP_VALID_MASK 做特性判断,改用 cap_issubset() 比较6 个文件(ascend310/ascend910 container、dms_hotreset、uda_access、docker_query、urd_container)
指针容器container_of() 新增类型断言,const struct file * 触发 pointer type mismatch改用 container_of_const()(老内核走带 uintptr_t 转换的分支)davinci_intf_init.c
事件通知PROFILE_TASK_EXIT / profile_event_register() 随 profile 子系统移除#if defined(PROFILE_TASK_EXIT) 条件编译,保留旧内核路径logic_cq.cuda_access.c
定时器del_timer/del_timer_synctimer_delete_syncfrom_timer 删除;hrtimer_inithrtimer_setup逐处替换;hrtimer_setup 用版本分支保留老内核写法del_timer 7 处、from_timer 3 处、hrtimer_init 3 处
用户页(GUP)get_user_pages_remote() 去掉 vmas 参数(6 参)采用 ≥5.9 的 6 参调用形式svm_mem_mng.c
页表遍历follow_pfn() 删除;模块内 pte_offset_map() 依赖未导出的 __pte_offset_map封装 follow_pfnmap_start/end();改用 pte_offset_kernel()6 文件 7 处 + 2 文件 4 处
PCIe / MSIpci_enable/disable_pcie_error_reporting() 删除(AER 恒开);for_each_pci_msi_entry 删除本地空实现替代;改用 msi_for_each_desc() + __msi_lock/unlock_descs()devdrv_pci.c
内存/页nth_page() 删除展开为 pfn_to_page(page_to_pfn(p) + i)tsdrv_osal_mm.c
符号导出static(本地)符号 EXPORT_SYMBOL 成为错误无用的导出删除;确有外部用途的符号先改全局再导出dms_init.cdavinci_intf_init.c
构建系统EXTRA_CFLAGS 失效;stdarg.h/stdbool.h 无 libc 头;内核符号不透明化批量改 ccflags-y(48 个 Makefile/*.mk)、导出 HIAI_DKMS_DIR、补 gcc include 与 linux/stdarg.h构建层全量
其他class_create(THIS_MODULE,…)netif_napi_addPDE_DATA、`vm_flags=struct kernel_symbol` 不透明按新签名改写或降级为兼容桩

9.1 移植补丁的编译验证(改源码后必做)

修改源码后,不要直接跑安装器,而是先在独立副本里编译验证。这样可以快速定位问题,避免每次都等安装器走完整个流程。

cp -a /usr/src/davinci_hiai-1.0 /tmp/buildcheck
cd /tmp/buildcheck
make all KERNEL_UNAME=$(uname -r) DAVINCI_HIAI_DKMS=y TARGET_PRODUCT=mini TARGET_CHIP_ID=hi1910 \
  CUSTOM_OS_CCFLAGS="-I/usr/lib/gcc/x86_64-linux-gnu/15/include -Wno-error=missing-prototypes \
  -Wno-error=implicit-function-declaration -Wno-error=maybe-uninitialized" 2>&1 | tee /tmp/buildcheck.log

grep -c "error:" /tmp/buildcheck.log                                  # 期望 0
grep -o 'WARNING: modpost: "[^"]*" \[[^]]*\] undefined!' /tmp/buildcheck.log | sort -u   # 期望空

关键经验:必须同时看 modpost 的 undefined 符号。构建参数里 KBUILD_MODPOST_WARN=1 把"未定义符号"从错误降级为警告,编译能"全绿",但 modprobe 时会报 Unknown symbol。本项目就先后补掉了 hrtimer_init(改名 hrtimer_setup)与一处被误放进 #ifdef CFG_FEATURE_VFIO 内的辅助函数。

十、验证结果

10.1 编译与安装

$ dkms status
davinci_hiai/1.0, 7.0.0-31-generic, x86_64: installed

$ find /lib/modules/7.0.0-31-generic/updates/dkms -name "*.ko.zst" | wc -l
22

10.2 运行状态(冷启动后)

npu-smi info(节选):

+-------------------------------+-----------------+------------------------------------------------------+
| NPU     Name                  | Health          | Power(W)     Temp(C)           Hugepages-Usage(page) |
| Chip    Device                | Bus-Id          | AICore(%)    Memory-Usage(MB)                        |
+===============================+=================+======================================================+
| 88      310                   | OK              | 12.8         68                0     / 969           |
| 0       0                     | 0000:00:0B.0    | 0            577  / 7759                             |
| 96      310                   | OK              | 12.8         62                0     / 969           |
| 0       1                     | 0000:00:0C.0    | 0            575  / 7759                             |
| ...(共 10 张:Chip 88/96/104/112/120/128/136/144/152/160,Device 0–9)                     |

其余实测数据:

$ dmesg | grep -c "Set device boot finish"
10
$ /usr/local/Ascend/driver/tools/upgrade-tool --device_index -1 --system_version
Get system version(23.0.0) succeed, deviceId(0..9)

10.3 版本配套

组件版本配套要求结果
驱动23.0.0固件 [7.0.0, 7.1.99]
固件7.1.0.3.220驱动 [23.0.rc3, 23.0.0]✅ 双向满足
npu-smi23.0.0

十一、踩坑记录与规避

#现象规避
1.run 覆盖补丁源码改完源码重跑安装器,补丁全部丢失,编译报 drv_log.h: No such file--noexec --extract 解包 → 替换 payload/driver/kernel → 跑 install.sh
2install.sh 参数格式直接 bash install.sh --fullUnrecognized parameters前两参必须是 (run 包名, ".//绝对路径"),脚本会截掉前两个字符得到绝对路径
3install.info 重复写入install path /usr/local/Ascend /usr/local not exists按 key 去重 /etc/ascend_install.info
4modpost 未定义符号被降级编译全绿,modprobeUnknown symbol hrtimer_init构建后强制检查 undefined! 列表,要求为空
5固件下发期间卸载模块卡停在异常态,探针报 Wait boot mode from bios time outupgrade-toolNone of the chips are up不要在驱动加载/下发镜像过程中 rmmod;异常后用整机重启恢复
6沙箱/权限拦截安装器写 /usr/local/etc/lib/modules 时被拦安装动作需在无沙箱/特权环境执行
7安装目录被加 immutable 属性安装完成后,/usr/local/Ascend/driver/kernel 下 1600+ 文件被 chattr +i;再次覆盖时 rsync/cp 报 Operation not permitted覆盖前先 chattr -iR /usr/local/Ascend/driver/kernel(官方 install.sh:943 也是这么做的)
8重装时安装器交互等待已装过驱动时会问 do you want to continue? [y/n],非交互环境下进程挂在管道读上(无任何日志输出)用管道喂答案:printf 'y\ny\ny\n' | bash driver/script/install.sh ...,或加 --quiet

十二、功能取舍与风险

以下为内核 7.0 缺少对应能力而做出的有意取舍,不影响编译、加载与设备识别:

  1. 进程退出清理钩子缺失PROFILE_TASK_EXIT 通知器(logic_cq 的等待 TID 清理、uda 的 NS 节点回收)在新内核不可用,已条件编译关闭。极端情况下若用户进程在等待中途被强杀,可能残留少量等待表项。
  2. PTE 读取无锁svmdrvpte_offset_map()(模块不可用)改为 pte_offset_kernel(),与旧驱动同样不持 PTE 锁。
  3. PCIe AER 开关变为空实现:新内核 AER 恒开,pci_enable/disable_pcie_error_reporting() 由本地空函数替代。
  4. follow_pfn 语义替换follow_pfnmap_start/end() 仅支持 VM_IO|VM_PFNMAP 映射,与原 follow_pfn 的适用面一致;逐页调用相比原实现略有开销。

十三、结论与交付物

本次移植的核心结论:

  • 该驱动在内核 7.0 上的不兼容点全部属于 API 迁移类,无架构性阻塞;共处理 30+ 处、跨 40 余个文件(含 48 个构建文件)。
  • 迁移成功的关键工程经验有三条:
    1. 用独立副本做编译验证并检查 modpost 未定义符号——这是发现 hrtimer_init 等漏网之鱼的唯一可靠手段;
    2. 不要与安装器的覆盖行为对抗,而要把补丁替换进它的 payload——这是避免补丁被反复抹掉的关键;
    3. 芯片类驱动必须用整机重启完成状态复位与固件生效——任何模块级别的卸载/重载都可能使卡停在异常态。

交付物清单

  • 本手册:/root/docs/昇腾310P驱动安装手册(含移植实录).md
  • 移植后的驱动源码:/usr/src/davinci_hiai-1.0(与 /usr/local/Ascend/driver/kernel 同步)
  • 源码备份(供新机器恢复):/root/docs/davinci_hiai-1.0-patched.tar.gz(3.1 MB)
  • 已安装内核模块:/lib/modules/7.0.0-31-generic/updates/dkms/(22 个)

附录:装完之后怎么用

npu-smi info                        # 看卡的总体状态(型号/温度/功耗/显存/健康)
npu-smi info -t usages -i 0         # 看 0 号卡的利用率
watch -n 2 npu-smi info             # 每 2 秒刷新

关键词标签:昇腾310P、Ascend NPU、A300-3010、驱动移植、内核7.0、Ubuntu 26.04、DKMS、npu-smi、华为昇腾、内核开发

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐