Skip to content

设备树故障处理案例

案例 1:驱动 probe 未被调用

排查

bash
# 1. 确认设备树节点存在
ls /sys/firmware/devicetree/base/soc/

# 2. 检查 compatible 是否匹配
cat /sys/firmware/devicetree/base/soc/serial@fe201000/compatible

# 3. 检查 status
cat /sys/firmware/devicetree/base/soc/serial@fe201000/status
# 必须是 "okay" 或 "ok"

# 4. 查看 platform 设备列表
ls /sys/bus/platform/devices/ | grep fe201000

# 5. 查看驱动匹配情况
ls /sys/bus/platform/drivers/my-uart/

常见原因

原因解决
status = "disabled"在板级 dts 中改为 "okay"
compatible 字符串拼写错误逐字符对比 DTS 和 of_match_table
DTB 未更新重新编译并烧录 DTB
驱动模块未加载modprobe my-uart

案例 2:reg 地址映射失败

现象devm_ioremap_resource 返回 -EBUSY-EINVAL

排查

bash
# 查看 iomem 分配情况
cat /proc/iomem | grep fe201000

# 检查 DTS 中 reg 格式
dtc -I fs /sys/firmware/devicetree/base | grep -A5 "serial@fe201000"

常见原因

c
/* ❌ 错误:#address-cells=<1> 但写了 64 位地址 */
soc {
    #address-cells = <1>;
    uart@fe201000 {
        reg = <0x0 0xfe201000 0x0 0x1000>;  /* 4 个 cell,但父节点期望 2 个 */
    };
};

/* ✅ 正确 */
soc {
    #address-cells = <1>;
    #size-cells = <1>;
    uart@fe201000 {
        reg = <0xfe201000 0x1000>;
    };
};

案例 3:中断号获取失败

现象platform_get_irq() 返回负值。

排查

bash
# 查看中断属性
cat /sys/firmware/devicetree/base/soc/serial@fe201000/interrupts | xxd

# 查看 interrupt-parent
cat /sys/firmware/devicetree/base/soc/serial@fe201000/interrupt-parent | xxd

常见原因

c
/* ❌ 错误:GIC SPI 中断号从 0 开始,但硬件手册从 32 开始 */
/* 硬件手册说 IRQ 64,DTS 中应写 64-32=32 */
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;  /* 错误 */
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;  /* 正确 */

/* ❌ 错误:缺少 interrupt-parent */
/* 如果节点不在 GIC 的子树下,需要显式指定 */
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;

案例 4:时钟获取失败

现象devm_clk_get() 返回 -ENOENT

bash
# 查看时钟属性
cat /sys/firmware/devicetree/base/soc/serial@fe201000/clock-names

常见原因

c
/* ❌ clock-names 与驱动中请求的名称不一致 */
/* DTS */
clock-names = "pclk";   /* 写的是 pclk */

/* 驱动 */
clk = devm_clk_get(dev, "uart_clk");  /* 请求的是 uart_clk */

/* ✅ 保持一致 */
clock-names = "uart_clk";

案例 5:GPIO 获取失败

现象devm_gpiod_get() 返回 -ENOENT-EPROBE_DEFER

c
/* ❌ 属性名不符合规范 */
my-gpio = <&gpio 10 GPIO_ACTIVE_LOW>;

/* 驱动中 */
gpiod_get(dev, "my", GPIOD_OUT_LOW);  /* 会查找 "my-gpios" 属性 */

/* ✅ 属性名必须以 -gpios 结尾(单个也可用 -gpio) */
reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
/* 驱动中 */
gpiod_get(dev, "reset", GPIOD_OUT_LOW);  /* 查找 "reset-gpios" */

案例 6:DTB 与内核版本不匹配

现象:启动时出现 OF: fdt: No chosen node found 或设备无法识别。

bash
# 检查 DTB 版本信息
fdtget /boot/dtb/myboard.dtb / model

# 重新编译 DTB(在内核源码目录)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
# 生成在 arch/arm64/boot/dts/myvendor/myboard.dtb

褚成志的笔记