4. 驱动日志配置与错误排查

任务说明

本案例面向NPU驱动加载失败场景:系统启动或驱动插入时,insmod/modprobe返回错误,但默认日志级别下看不到有效线索。目标是通过配置驱动日志级别,捕获完整错误信息,并依据日志定位根因(如固件缺失、地址冲突、电源时序等)。完成本案例后,你将掌握驱动日志系统的控制方法,并具备独立排查加载失败的基本路径。

驱动日志框架与级别说明

NPU驱动通常基于Linux内核日志框架。日志级别由低到高为:DEBUG(7)、INFO(6)、NOTICE(5)、WARNING(4)、ERROR(3)。驱动加载失败的关键信息多出现在INFO至ERROR区间,而定位根因往往需要DEBUG级信息(如寄存器读写序列、固件加载路径)。内核默认console_loglevel通常为4(仅显示WARNING及以上),导致INFO级加载流程和DEBUG级细节被丢弃。

日志级别配置方法

本案例提供两种配置路径:运行时通过procfs调整内核日志阈值,以及编译期通过驱动模块参数启用调试输出。前者适用于现场快速排查,后者适用于需要持久化调试的场景。以下实现聚焦运行时配置,因为它无需重新编译驱动,可直接作用于当前故障环境。

实现:日志级别控制脚本

创建一个Shell脚本npu_log_config.sh,用于查看和调整NPU驱动相关日志级别,并在加载失败时自动捕获完整日志到文件:


#!/bin/bash
# 文件: npu_log_config.sh
# 功能: 配置NPU驱动日志级别并捕获加载错误日志
# 用法: ./npu_log_config.sh [debug|info|warn|error]

# 日志保存路径
LOG_FILE="/var/log/npu_driver_load.log"

# 获取当前控制台日志级别
get_console_level() {
    cat /proc/sys/kernel/printk | awk '{print $1}'
}

# 设置控制台日志级别
# 参数: 级别数字 (7=debug, 6=info, 4=warn, 3=error)
set_console_level() {
    local level=$1
    # 同时设置控制台和默认日志级别
    echo "$level $level" > /proc/sys/kernel/printk 2>/dev/null
    if [ $? -eq 0 ]; then
        echo "[OK] 控制台日志级别已设置为: $level"
    else
        echo "[FAIL] 设置失败,请以root权限运行"
        exit 1
    fi
}

# 根据参数映射日志级别
map_level() {
    case "$1" in
        debug) echo 7 ;;
        info)  echo 6 ;;
        warn)  echo 4 ;;
        error) echo 3 ;;
        *)     echo "无效级别: $1 (可选: debug/info/warn/error)"; exit 1 ;;
    esac
}

# 主流程
echo "=== NPU驱动日志配置工具 ==="
echo "当前控制台日志级别: $(get_console_level) (7=debug, 6=info, 4=warn, 3=error)"

# 如果提供了级别参数,则进行设置
if [ $# -eq 1 ]; then
    LEVEL_NUM=$(map_level "$1")
    set_console_level "$LEVEL_NUM"
    echo "提示: 日志级别已调整,现在可以尝试加载驱动并观察输出"
    echo "建议执行: modprobe npu_driver 或 insmod /path/to/npu_driver.ko"
    echo "完整日志将保存至: $LOG_FILE"
else
    echo "用法: $0 [debug|info|warn|error]"
    echo "示例: $0 debug   # 开启最详细日志,用于排查加载失败"
fi

# 捕获dmesg中与npu相关的最近日志
echo ""
echo "=== 最近NPU相关内核日志 ==="
dmesg | grep -i "npu\|npudrv" | tail -30 > "$LOG_FILE" 2>&1
if [ -s "$LOG_FILE" ]; then
    cat "$LOG_FILE"
else
    echo "(暂无NPU相关日志,驱动可能未加载或日志已被清除)"
fi

驱动加载失败排查流程

将上述脚本保存后赋予执行权限:chmod +x npu_log_config.sh。排查时按以下步骤操作:

  1. 以root身份运行./npu_log_config.sh debug,将日志级别调至最高;
  2. 执行modprobe npu_driver(或实际驱动名)触发加载;
  3. 观察终端输出或查看/var/log/npu_driver_load.log;
  4. 根据日志关键字定位根因:firmware not found表示固件路径错误;resource busy表示IO地址或中断冲突;timeout表示硬件未就绪;unknown symbol表示依赖模块缺失。

验证方法与判定标准

验证步骤:

  1. 运行./npu_log_config.sh(不带参数),确认输出显示当前日志级别;
  2. 运行./npu_log_config.sh debug,再次不带参数运行,确认级别已变为7;
  3. 尝试加载驱动,观察是否出现比默认级别更详细的日志输出;
  4. 检查/var/log/npu_driver_load.log文件是否已生成且包含时间戳和日志级别字段。

判定标准:

  • 脚本能正确读取并修改/proc/sys/kernel/printk中的日志级别值;
  • 设置debug级别后,驱动加载时内核输出的信息量明显多于默认级别(出现INFO或DEBUG级条目);
  • 日志文件成功捕获包含npu关键字的最近内核日志;
  • 若驱动加载失败,日志中能定位到具体错误原因(如文件缺失、资源冲突等),而非仅有笼统的failed提示。
NPU驱动加载失败日志排查流程 默认日志级别 console=4 (WARNING) ./npu_log_config.sh debug 设置printk级别=7 modprobe npu_driver 触发加载流程 dmesg 捕获示例 (debug级别): [ 1.234567] npu: loading out-of-tree module taints kernel. [ 1.234890] npu: NPU_DRV: probe start, pci_dev=0000:01:00.0 [ 1.235102] npu: NPU_DRV: firmware file 'npu_fw.bin' not found in /lib/firmware/ [ 1.235200] npu: NPU_DRV: probe failed with error -2 根因判定: 关键字 "firmware not found" → 固件缺失或路径错误 解决: 将固件复制到 /lib/firmware/ 或修改驱动固件路径参数 验证: 重新加载驱动,观察是否出现 "probe success"

常见错误与日志特征对照

下表列出驱动加载失败的典型日志特征与对应根因,便于快速定位:


日志关键字                     | 根因方向
------------------------------|-----------------------------
firmware not found            | 固件文件缺失或路径配置错误
resource busy / conflict      | IO地址、中断号或DMA通道冲突
unknown symbol                | 依赖的内核模块未加载或版本不匹配
timeout / no response         | 硬件未上电、PCIe链路异常或复位不完整
permission denied             | 设备节点权限或SELinux策略限制

注意事项

日志级别设置仅对当前运行内核生效,重启后恢复默认值。若需持久化,可将echo "7 7" > /proc/sys/kernel/printk写入/etc/rc.local或systemd服务中。排查完成后建议将日志级别恢复为4,避免生产环境因大量调试日志影响性能。若驱动加载失败导致系统日志环形缓冲区被覆盖,可在加载前先执行dmesg -c清空缓冲区,确保捕获的日志从本次加载开始。