最近帮客户在openEuler 22.03 LTS上交付了一套昇腾910B AI训练环境,过程比想象中曲折不少。前前后后折腾了几个晚上,从初始驱动装不上、MCU版本不匹配导致设备掉线,到最后把驱动、固件、MCU升级流程彻底摸透,整理出一套带自动脚本的完整安装流程。这篇文章就把这次实操完整记录下来,包括环境检查、软件包选型、脚本设计、MCU升级的触发机制,以及npu-smi验证细节,给同样在国产服务器上做昇腾环境的朋友做个参考。
先说清楚你的目标:如果服务器刚到手,前面插了一张910B的PCIe卡,系统是openEuler 22.03 LTS,那么这张卡默认是没法直接用的。昇腾硬件和普通GPU不一样,板卡上不仅有计算用的NPU,还有一个独立的MCU(微控制单元)负责整块板的电源管理、温度监控和风扇策略。开箱后的板卡,MCU固件是出厂版本,跟新版驱动往往不匹配,你必须按顺序完成驱动安装、固件升级和MCU升级,硬件才能在Linux上稳定工作。下面就是一条龙解决这三个环节的实操记录。
1. 驱动、固件和MCU到底管什么:先把升级顺序想明白
在跑脚本之前,强烈建议你先搞清这层软件栈的关系,否则遇到问题会很难定位。
1.1 昇腾910B上的两套处理核心:NPU与MCU
昇腾910B不是一颗简单的加速芯片,它是一整块复杂的板卡。板上除了计算用的NPU,还有内存颗粒、电源管理模块、温度传感器,以及一颗专门负责“伺候”这些硬件的微控制器,也就是MCU。MCU在板卡里扮演的是“管家”角色:上电时序由它控制,每一路供电电压由它监控,传感器温度和风扇转速由它上报,甚至板卡的序列号、版本号信息也由它存储。
最关键的一点是,MCU是独立于NPU计算单元运行的。它有自己的固件,通过低速总线跟主控侧通信。驱动加载时,真正跟NPU芯片交互的是NPU固件;而驱动能否成功初始化PCIe设备、能否正确读取板卡信息,依赖的是MCU固件。两套固件同时正常,板卡才处于健康状态。
1.2 为什么顺序不能乱:先驱动,再固件
实际操作中,安装顺序有先驱动后固件和先固件后驱动两派。根据官方手册和这次实测下来的结论,建议顺序是:先装驱动,再装固件,因为固件包内部包含MCU升级流程。
这个顺序背后的逻辑是:
- 驱动安装成功后,操作系统的PCIe子系统才能正确识别910B设备,生成 /dev/davinci0 等设备节点。
- 固件升级工具需要借助驱动提供的系统接口和板卡通信,否则它无法访问设备的控制通道。
- 固件包升级时会自动检测当前MCU版本,发现版本低于包内自带版本时执行MCU升级。驱动先行能保证这个检测和升级过程顺利。
如果你上来就刷固件,而驱动还没装或没正确加载,大部分固件包会直接报“no device found”。这不是包坏了,是顺序没搞对。
1.3 版本匹配的底层逻辑
昇腾HDK软件包命名有规律,比如Ascend-hdk-910b-npu-driver_23.0.rc1_linux-aarch64.run,其中23.0.rc1就是大版本号。驱动和固件必须处在同一个大版本内,驱动是24.0、固件是23.0的话,驱动加载后照样会报固件版本过低的错误。
MCU固件不会单独给一个下载链接,而是打包在固件run文件里。所谓“MCU升级”,本质上是固件安装过程中,检测到MCU版本不一致时自动触发的一次组件更新。固件安装脚本的执行顺序是:NPU固件版本检查 → MCU固件版本检查 → 按需升级MCU → 写入固件存储 → 复位板卡。
| 组件 | 文件形态 | 安装方式 | 升级结果 |
|---|---|---|---|
| 驱动 | driver的.run包 | --full | 内核模块加载,/dev/davinci* 出现 |
| NPU固件 | firmware的.run包 | --full | 芯片固件更新,算力状态正常 |
| MCU固件 | 打包在firmware包内 | 固件安装时自动触发 | 电源/温度监控、板管理功能正常 |
MCU升级时,板卡会有一个短暂断电重启的过程,系统日志能看到相关I2C设备重新枚举,风扇会瞬间满转。这是正常现象,只要不是反复失败,不用慌。
2. 环境准备与软件包获取:动手前把这些坑先填平
2.1 操作系统与架构确认
打开终端先执行两条命令:
cat /etc/openEuler-release uname -m正常输出类似:
openEuler release 22.03 (LTS) aarch64昇腾910B驱动主要提供aarch64架构版本。如果你的服务器是x86平台,需要确认板卡是否支持x86环境。本文场景默认是ARM架构,也就是鲲鹏加昇腾的经典组合。
再看内核版本:
uname -ropenEuler 22.03 LTS默认内核一般是5.10.x。驱动安装时通过dkms编译模块或加载预编译ko,因此内核开发包必须和当前运行内核严格一致,这一点后面会反复提到。
2.2 下载昇腾HDK软件包并校验
从昇腾社区官网下载软件包时,需要拿两类文件:
Ascend-hdk-910b-npu-driver_x.x.x_linux-aarch64.runAscend-hdk-910b-npu-firmware_x.x.x_linux.run
下载后务必做完整性校验:
sha256sum Ascend-hdk-910b-npu-driver_*.run拿这个结果去对比官网公布的校验值。这一步别省,网络传输导致文件损坏或被人篡改的情况不是没发生过。校验不一致的包,装上去了也是各种稀奇古怪的报错。
2.3 安装编译依赖与清理旧驱动
昇腾驱动编译需要内核头文件和工具链:
sudo yum install -y gcc gcc-c++ make dkms sudo yum install -y kernel-devel-$(uname -r) kernel-headers-$(uname -r)如果yum报错找不到kernel-devel-$(uname -r),先尝试安装通用包:
sudo yum install -y kernel-devel kernel-headers然后检查源码目录是否存在:
ls /usr/src/kernels/$(uname -r)这个目录不存在或为空,驱动编译基本必失败,是昇腾安装里最常踩的坑之一。
旧驱动清理同样重要。之前装过旧版昇腾驱动,没有卸载干净就装新版,老ko模块会和新模块冲突,加载时报“File exists”。标准卸载命令是:
sudo /usr/local/Ascend/driver/script/uninstall.sh --uninstall sudo rm -rf /usr/local/Ascend清理之后最好重启一次再继续,避免残留的内核模块状态影响新驱动加载。
3. 手写一键升级脚本:从裸机到可用环境的自动化
3.1 脚本设计思路
为什么不直接手动敲两条命令,非要写脚本?因为整个升级过程的检查点太多,任何一环失败后面都要重新排查。脚本把常见检查、清理、安装、验证步骤固化,既保证流程可复现,也让新认识的朋友或团队同事能在一台新服务器上快速完成部署。
脚本按六个步骤设计:
- 权限和前置条件检查
- 旧环境清理
- 安装编译依赖
- 安装驱动包
- 安装固件包(覆盖MCU升级)
- 设置环境变量与输出验证信息
每个步骤写日志到/var/log/ascend_upgrade/,便于事后回溯。任何一步失败立即退出并打印明确错误,不继续往下执行。
3.2 MCU升级在脚本里的处理方式
MCU升级没有独立的公开命令,它是固件安装包执行到某个阶段时弹出交互提示,询问是否升级MCU。自动化的处理方式,是通过管道往固件安装脚本里喂y应答,让它顺着提示走默认升级流程。
我实测下来,yes |方式在昇腾固件包上稳定有效。这也符合运维里常见的“交互式安装转自动化”套路。如果你更习惯手动安装,在固件包提示时输入y即可,效果一样。
3.3 完整脚本代码
下面是脚本全文,保存为ascend_910b_upgrade.sh:
#!/bin/bash set -euo pipefail # ============================================================= # 昇腾910B 驱动 + 固件 + MCU 升级脚本 (openEuler 22.03 LTS) # 用法: sudo bash ascend_910b_upgrade.sh <driver.run> <firmware.run> # 示例: sudo bash ascend_910b_upgrade.sh \ # Ascend-hdk-910b-npu-driver_23.0.rc1_linux-aarch64.run \ # Ascend-hdk-910b-npu-firmware_23.0.rc1_linux.run # ============================================================= DRIVER_PKG="${1:-}" FIRMWARE_PKG="${2:-}" ARCH="$(uname -m)" LOG_DIR="/var/log/ascend_upgrade" LOG_FILE="$LOG_DIR/upgrade_$(date +%Y%m%d_%H%M%S).log" mkdir -p "$LOG_DIR" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" } fail() { log "[ERROR] $*" exit 1 } # 1. 权限检查 if [ "$(id -u)" -ne 0 ]; then fail "必须使用root权限执行,建议: sudo bash $0 <driver.run> <firmware.run>" fi # 2. 参数检查 if [ -z "$DRIVER_PKG" ] || [ ! -f "$DRIVER_PKG" ]; then fail "第一个参数必须指定driver.run文件路径" fi if [ -z "$FIRMWARE_PKG" ] || [ ! -f "$FIRMWARE_PKG" ]; then fail "第二个参数必须指定firmware.run文件路径" fi # 3. 架构检查 if [ "$ARCH" != "aarch64" ]; then fail "当前架构是 $ARCH,昇腾910B驱动仅支持 aarch64" fi # 4. 操作系统提示 if [ ! -f /etc/openEuler-release ]; then log "警告: 当前系统不是openEuler,若继续执行请自担风险" fi # 5. 定位run文件所在目录 SCRIPT_DIR="$(cd "$(dirname "$DRIVER_PKG")" && pwd)" DRIVER_NAME="$(basename "$DRIVER_PKG")" FIRMWARE_NAME="$(basename "$FIRMWARE_PKG")" cd "$SCRIPT_DIR" chmod +x "$DRIVER_NAME" "$FIRMWARE_NAME" log "========== 昇腾910B 升级开始 ==========" log "驱动包 : $DRIVER_NAME" log "固件包 : $FIRMWARE_NAME" log "日志 : $LOG_FILE" # 6. 清理旧驱动 if [ -d /usr/local/Ascend/driver ]; then log "检测到已有旧版驱动,开始卸载..." if [ -x /usr/local/Ascend/driver/script/uninstall.sh ]; then /usr/local/Ascend/driver/script/uninstall.sh --uninstall || log "卸载脚本返回非0,继续尝试清理" fi rm -rf /usr/local/Ascend log "旧驱动已清理,建议清理后重启一次再继续安装" fi # 7. 安装编译依赖 log "安装编译依赖..." if command -v dnf >/dev/null 2>&1; then dnf install -y gcc gcc-c++ make dkms \ kernel-devel-"$(uname -r)" kernel-headers-"$(uname -r)" || true else yum install -y gcc gcc-c++ make dkms \ kernel-devel-"$(uname -r)" kernel-headers-"$(uname -r)" || true fi if [ ! -d "/usr/src/kernels/$(uname -r)" ]; then log "警告: 未找到 /usr/src/kernels/$(uname -r),驱动编译可能失败" fi # 8. 安装驱动 log "开始安装驱动: $DRIVER_NAME" if yes | "$SCRIPT_DIR/$DRIVER_NAME" --full >> "$LOG_FILE" 2>&1; then log "驱动安装成功" else fail "驱动安装失败,请查看日志 $LOG_FILE" fi # 9. 安装固件(含MCU升级) log "开始安装固件(含MCU升级): $FIRMWARE_NAME" if yes | "$SCRIPT_DIR/$FIRMWARE_NAME" --full >> "$LOG_FILE" 2>&1; then log "固件安装成功,MCU升级流程已执行" else fail "固件安装失败,请查看日志 $LOG_FILE" fi # 10. 设置环境变量 log "配置环境变量..." cat > /etc/profile.d/ascend-env.sh <<'EOF' export ASCEND_HOME=/usr/local/Ascend export PATH=$ASCEND_HOME/driver/tools:$PATH export LD_LIBRARY_PATH=$ASCEND_HOME/driver/lib64:$LD_LIBRARY_PATH EOF chmod +x /etc/profile.d/ascend-env.sh source /etc/profile.d/ascend-env.sh # 11. 验证 log "========== 安装完成,输出设备信息 ==========" if command -v npu-smi >/dev/null 2>&1; then npu-smi info | tee -a "$LOG_FILE" || \ log "提示: npu-smi 暂时无法获取设备信息,可能需重启后生效" else log "未找到 npu-smi 命令,请检查驱动安装路径" fi log "========== 脚本执行结束 ==========" log "如果上面没有看到设备信息,执行: sudo reboot 后再运行 npu-smi info 验证"3.4 脚本关键段解释
有几点需要重点理解,不然脚本换到别的环境还是会踩坑。
set -euo pipefail:这一行是脚本的保险丝。set -e让任何命令返回非0时中断脚本;set -u让未定义变量直接报错;set -o pipefail保证管道中任意一段失败都能被捕获。对安装类脚本,这个组合特别关键,因为很多失败藏在管道深处,不开启这个选项你根本发现不了。
第6步旧驱动清理:卸载脚本可能因为系统服务状态返回非0,所以管道里用了|| log避免脚本因为卸载脚本的小问题卡死。但清理动作本身不能跳过,否则后面安装新驱动会撞上“insmod failed: File exists”的问题。
第7步依赖安装:openEuler 22.03的软件源在不同镜像上差异明显,依赖安装失败我故意不让脚本立即退出,而是保留后续检查。真正的硬性条件是/usr/src/kernels/$(uname -r)目录存在,那是dkms编译模块需要的内核头文件位置。这个检查比依赖安装命令本身更能反映真实问题。
第8、9步yes |:固件run安装脚本检测到MCU版本落后时会弹出确认,用yes自动应答所有确认问题。这是一个很基础的自动化技巧,但对昇腾固件包就是有效。装完你会看到日志里记录MCU升级成功的信息。
第10步环境变量:昇腾默认装到/usr/local/Ascend/driver,把tools和lib64加进 PATH 与 LD_LIBRARY_PATH,之后直接敲npu-smi就能用,不用每次都写全路径。
3.5 为什么脚本里没有单独的“MCU升级命令”
这是标题里最容易被误解的地方。很多人以为MCU升级有一条独立命令,实际上在昇腾910B的HDK固件包里,MCU升级是固件安装脚本内部编排的步骤。固件包安装会依次执行:NPU固件版本检查 → MCU固件版本检查 → 按需MCU升级 → 写入固件存储 → 复位板卡。外部只需要给它一个“同意升级”的应答。
如果真需要手动单独升级MCU,一般是先从固件包解压目录里找到mcu固件文件(可能是.hex或.bin格式),再进入板卡维护模式刷新。但这种操作只适用于MCU已经损坏、必须通过底层工具恢复的场景,正常业务部署不用走这条路。
4. 执行升级与结果验证:npu-smi怎么用才算真的会用了
4.1 脚本执行参考
把两个run文件放到同一个目录,然后执行:
sudo bash ascend_910b_upgrade.sh \ Ascend-hdk-910b-npu-driver_23.0.rc1_linux-aarch64.run \ Ascend-hdk-910b-npu-firmware_23.0.rc1_linux.run执行过程会滚动输出日志。如果一切正常,最后几行会显示npu-smi抓到的设备信息:
[2025-01-12 15:22:33] ========== 安装完成,输出设备信息 ========== [2025-01-12 15:22:34] NPU ID ... Chip Count ... Total NPU Count ...4.2 npu-smi基础检查
脚本结束不重启的情况下,设备节点可能还没完全就绪,先重启:
sudo reboot重启后第一件事:
npu-smi info正常输出会列出NPU卡数量、每张卡的温度、内存使用和算力状态。核心看这几个字段:
- Chip Count:板上的芯片数量,910B单卡通常是1或2
- Temperature:温度在合理区间,比如40度到70度之间
- Memory Usage:显存是否正确识别,显示0或异常值说明固件没刷到位
- AI Core状态:算力核是否正常
想查看更详细的板卡信息,包括MCU版本,执行:
npu-smi info -t board -i 0这里-t是type,-i是设备ID。输出里会有PCB版本、固件版本、MCU版本等字段。把这些版本号记下来,跟HDK发布注记做对照,确认升级已生效。
再看内核模块是否加载:
lsmod | grep drv_出现drv_mcu、drv_pcie、drv_davinci等模块,说明驱动加载成功。如果没有任何输出,需要检查dmesg和内核版本。
4.3 MCU和固件版本的验证细节
固件包安装完不代表MCU一定升级了。有一种情况:MCU当前版本和固件包要求版本一致时,固件脚本会跳过MCU升级,日志里会写类似“MCU version is already up to date, skip”。如果就是想强制刷新MCU,才需要单独手段。正常业务场景不做强制刷写。
MCU升级失败时会有典型现象:npu-smi info找不到设备,因为驱动依赖的MCU通信没正常起来;或者系统日志出现大量“mcu response timeout”、“i2c transfer error”。排查方向放在第5章。
还有一个容易忽略的点:昇腾驱动安装后默认创建名为HwHiAiUser的用户组。普通用户想调用NPU,需要加入这个组:
sudo usermod -a -G HwHiAiUser $USER退出重新登录生效。不然后续跑训练程序会遇到权限报错。
5. 常见失败路径与修复清单
5.1 失败场景对照表
| 症状 | 可能原因 | 解决思路 |
|---|---|---|
| 驱动安装时找不到内核头文件 | kernel-devel未装或版本不匹配 | 重新安装kernel-devel-$(uname -r),确认/usr/src/kernels/$(uname -r)存在 |
| insmod failed: File exists | 旧驱动未清理 | 卸载旧驱动,删除 /usr/local/Ascend,重启后重试 |
| npu-smi找不到设备 | MCU升级失败或驱动未加载 | 查看dmesg,重新执行固件安装;必要时进紧急维护模式恢复MCU |
| MCU response timeout | MCU固件损坏或升级中断 | 重新执行固件包升级,过程中避免断电 |
| 重启后 /dev/davinci0 不存在 | 驱动模块未自动加载 | 检查模块加载状态,手动modprobe drv_pcie drv_mcu验证 |
| 固件包安装报 no device found | 驱动没装或设备没被系统识别 | 确认卡已插好,BIOS里PCIe识别正常,再装驱动 |
| Secure Boot开启导致模块加载失败 | 驱动模块未签名 | 进BIOS关闭Secure Boot后重启 |
5.2 MCU升级中断的恢复方法
MCU升级最怕中断。如果刷写过程中突然断电或系统崩溃,MCU可能进入半砖状态,NPU设备无法工作。不必太紧张,一般可以这样恢复:
- 把服务器完全断电,等待30秒再上电。
- 如果服务器有带外管理接口,登录管理页面的固件升级入口,选择固件包中的MCU固件文件强制刷写。
- 如果是普通PCIe服务器没有带外升级能力,用固件包解压后的scripts目录里的恢复脚本处理,比如
recover_xxx.sh之类。
这个环节宁可慢不能急,MCU刷写过程绝对不要断电。
5.3 驱动模块加载失败快速定位
模块加载失败时,第一步看内核日志:
dmesg | tail -100如果看到“No space left on device”,一般是板卡存储空间不足,核对固件包版本与当前硬件容量。如果看到“Operation not permitted”,大概率是Secure Boot没关。昇腾驱动模块没有在UEFI Secure Boot下签名,必须到BIOS里关掉Secure Boot,否则内核模块无法加载。新服务器的BIOS默认可能开着,这也是一个相当常见的新手坑。
5.4 一个容易误导人的场景:npu-smi正常但训练程序跑不起来
还有一种让人印象深刻的场景:npu-smi info看起来一切正常,卡也列得出来,但跑训练任务时进程直接挂掉,提示“device init failed”或“stream init failed”。这类问题多半不在驱动和MCU本身,而是驱动版本和CANN工具包版本不匹配。
昇腾的驱动、固件、CANN三者之间有严格的版本对应关系表,装完底层驱动和固件只是第一步,真正要跑训练还需要安装对应版本的CANN工具包。安装前先查版本配套表,别只看“最新版”就往上装。
6. 最后分享一点实操体会
整套流程走完,我的最大感受是:昇腾910B这套环境本身并不难,难的是信息不集中。官方文档分散在不同页面,版本对应关系表藏得深,升级顺序稍不留神就乱了。把自动化脚本沉淀下来之后,后来再在新服务器上重装整套环境,时间从三小时压到四十分钟左右,复制、执行、等结果就完事。
最后提醒一句:不管你是首次安装还是在做固件迭代升级,升级前把日志目录拷走备份,顺手拍一张产品序列号的照片,都是值得养成的习惯。MCU这种低层组件一旦出了问题,序列号和日志是最快的定位线索。祝大家都能顺利点亮手上的910B,把训练任务跑起来。