如何使用sysfs来排查驱动问题

张开发
2026/4/11 18:53:39 15 分钟阅读

分享文章

如何使用sysfs来排查驱动问题
原理性内容参考Linux文件管理源码相关总结-CSDN博客/sys概览先看下sys目录内容一般就是这些内容各个系统可能不太一样我们暂时熟悉一些通用的目录即可。/sys/devices这是整个 /sys 里最核心、最真实的目录/sys/devices 是内核把整个硬件拓扑结构1:1 映射成文件目录给你看。它不是按功能分类而是按 “谁挂在谁下面” 的真实硬件层级展示。比如主板 - 总线 - 控制器 - 设备 - 引脚/时钟/寄存器在 sysfs 里就是一层层目录。/sys/devices真实硬件拓扑按 “物理连接关系” 组织驱动开发、硬件排查用也看下有哪些子目录我们主要讲一些重点的通用的个别不一致的目录可能是不同的系统或者用户自定义的。逐类拆解每个目录是什么、从哪来、干嘛用1. 核心硬件拓扑类真实物理设备目录名含义来源核心用途platform平台总线设备根目录设备树 / 平台设备注册你之前看的ff634480.pwm、pinctrlff634480等所有片上外设、平台驱动都在这里是嵌入式驱动调试的核心目录system系统级核心设备CPU / 内核架构存放 CPU、时钟、中断控制器、总线等系统核心硬件比如cpu0、timer、interrupt-controllerarmv8_pmuv3ARMv8 架构性能监控单元PMUCPU 内核自带用于 CPU 性能计数、功耗监控、perf 工具采样是 ARM 架构的标准硬件调试单元2. 功能 / 子系统类按功能分类的设备目录名含义来源核心用途iio:device0工业 I/O 子系统设备IIO 驱动用于传感器ADC、陀螺仪、温湿度、红外等你的红外设备如果走 IIO 框架就会在这里生成设备节点方便用户态读取数据virtual虚拟设备根目录内核虚拟驱动存放无物理硬件对应的虚拟设备比如gpiochipGPIO 控制器虚拟节点、loop设备、veth网卡等3. 调试 / 追踪类内核调试工具目录名含义来源核心用途uprobe / breakpoint / kprobe / software / tracepoint内核追踪 / 探针设备ftrace/kprobe 子系统都是 Linux 内核动态追踪ftrace的底层设备节点用于•kprobe内核函数探针•uprobe用户态函数探针•tracepoint静态追踪点•breakpoint硬件断点•software软件事件如调度、内存perf、ftrace 工具的底层都依赖这些设备三、根目录的设计逻辑为什么这么分核心原则按「设备类型 归属」分层完全对应 Linux 设备模型真实物理硬件 →platform/system/armv8_pmuv3对应你板子上的真实芯片外设、CPU 核心是设备的「真身」。功能子系统 →iio:device0按功能归类方便应用层统一访问比如所有传感器都走 IIO 框架。虚拟设备 →virtual内核模拟的设备无物理硬件对应。调试工具 → 各类探针目录内核给开发者提供的动态追踪、性能调试接口属于调试专用。devices/platform/(平台总线)概况内容CPU 直接寻址的板载设备无传统总线。嵌入式 / ARM 开发板的绝大多数设备UART、I2C、SPI、GPIOx86 主板控制器RTC、电源管理、温度传感器用途嵌入式开发、底层硬件调试、设备树DT相关设备。你调试驱动90% 都在 platform 目录里。看下里面的内容这些奇怪命名比如ff634480.pwm、fixed-regulator0** 到底是怎么来的这些名字不是随便起的而是由设备树Device Tree内核驱动规则共同决定的。我把命名规则总结为“三大来源”你对照着看就能完全明白1. 第一类地址.编号形式最常见格式寄存器地址 序号例子ff634480.pwm、ff634480.gpio、ff634480.ir怎么来的来自设备树的reg属性设备树节点里有一段地址比如reg 0x0 0xff634480 0x100;。内核在加载时会把这个物理地址作为设备的唯一标识。自动追加序号如果同一块地址上挂载了多个子设备比如一个引脚控制器里有 PWM、GPIO 等内核会自动生成.0、.1、.2这样的编号。2. 第二类功能名 编号格式设备类型 数字例子fixed-regulator0、usbphy0、serial0怎么来的来自设备树的compatible兼容字符串比如设备树里写了compatible regulator-fixed;内核就知道这是个固定电压调节器就会把它归类叫fixed-regulator。自动计数系统中可能有多个固定调节器内核就按顺序编号fixed-regulator0、fixed-regulator1...3. 第三类自定义名字特殊格式任意名字例子aml_wifi、ble、jtag、vout怎么来的来自设备树节点的label或name如果设备树节点里明确写了label aml_wifi;或者节点名就叫wifi内核就会直接用这个名字。厂商自定义厂商比如Amlogic你用的平台为了好记会给设备起特定的名字。你的截图分析aml_wifiAmlogic 厂商定制的 WiFi 设备。ble蓝牙模块。jtag调试接口。vout视频输出。4. 为什么你会看到waiting_for_supplier你截图里最后有个waiting_for_supplier这其实是设备树依赖关系的显示含义这个设备正在等待它的供电设备regulator准备好。场景比如红外设备ir需要fixed-regulator0供电如果电源还没输出这里就会显示waiting_for_supplier。解决这说明你的红外驱动加载了但是电源还没起来属于正常启动过程或者检查一下 regulator 配置。总结一句话记住这些名字都是 ** 设备树DTB** 在启动时按物理地址、功能类型、厂商命名自动生成的 “身份证”。地址.编号 物理硬件映射功能名编号 设备功能分类自定义名 设备树节点起的名字你现在看你的红外设备假设叫ir它应该就在这个列表里如果没看到说明设备树可能没生效或者命名被隐藏了。一些iic spi设备在devices里面也有吗一般在哪个子目录下一、核心结论I2C/SPI 设备肯定在/sys/devices里位置分两种1. 物理总线视角真实硬件拓扑真身目录I2C/SPI 是硬件总线控制器设备会挂在对应总线控制器的父目录下这是设备的「真身」。典型路径Amlogic 晶晨平台和你当前环境完全匹配# I2C 设备真身路径 /sys/devices/platform/ff805000.i2c/i2c-0/ # 第0路I2C总线 /sys/devices/platform/ff805000.i2c/i2c-1/ # 第1路I2C总线 # 总线下面就是挂在这条总线上的具体I2C设备 /sys/devices/platform/ff805000.i2c/i2c-0/0-0048/ # I2C地址0x48的设备 # SPI 设备真身路径 /sys/devices/platform/ff800000.spi/spi_master/spi0/ # 第0路SPI总线 /sys/devices/platform/ff800000.spi/spi_master/spi0/spi0.0/ # SPI0.0设备片选0命名规则一眼识别I2C 总线目录i2c-总线号如i2c-0、i2c-1I2C 设备目录总线号-7位I2C地址如0-0048 总线 0地址 0x48SPI 总线目录spi_master/spi总线号如spi_master/spi0SPI 设备目录spi总线号.片选号如spi0.0 总线 0片选 02. 总线视角软链接方便统一查看内核会在/sys/bus/下生成软链接指向/sys/devices里的真身方便你按总线分类查看# I2C 总线视角 /sys/bus/i2c/devices/0-0048 - ../../devices/platform/ff805000.i2c/i2c-0/0-0048/ # SPI 总线视角 /sys/bus/spi/devices/spi0.0 - ../../devices/platform/ff800000.spi/spi_master/spi0/spi0.0/注意这只是软链接真实数据都在/sys/devices里修改属性只改真身目录即可。二、I2C/SPI 设备在/sys/devices里的完整层级以 Amlogic 为例1. I2C 层级结构/sys/devices/ └── platform/ └── ff805000.i2c/ # I2C控制器物理地址0xff805000来自设备树 ├── i2c-0/ # 第0路I2C总线 │ ├── 0-0048/ # 总线0上地址0x48的I2C设备真身 │ ├── 0-0050/ # 总线0上地址0x50的I2C设备 │ └── ... └── i2c-1/ # 第1路I2C总线 └── 1-0060/ # 总线1上地址0x60的I2C设备2. SPI 层级结构/sys/devices/ └── platform/ └── ff800000.spi/ # SPI控制器物理地址0xff800000来自设备树 └── spi_master/ ├── spi0/ # 第0路SPI总线 │ ├── spi0.0/ # SPI0片选0的设备 │ ├── spi0.1/ # SPI0片选1的设备 │ └── ... └── spi1/ # 第1路SPI总线 └── spi1.0/ # SPI1片选0的设备三、怎么快速找到你的 I2C/SPI 设备直接复制用的命令1. 找所有 I2C 总线和设备# 1. 列出所有I2C总线控制器看真身 ls /sys/devices/platform/*i2c* # 2. 列出所有I2C总线下的设备 ls /sys/devices/platform/*i2c*/i2c-* # 3. 快速查看所有I2C设备总线地址 ls /sys/bus/i2c/devices/ # 4. 查看某个I2C设备的详细信息以0-0048为例 cat /sys/bus/i2c/devices/0-0048/uevent cat /sys/bus/i2c/devices/0-0048/name2. 找所有 SPI 总线和设备# 1. 列出所有SPI总线控制器看真身 ls /sys/devices/platform/*spi* # 2. 列出所有SPI总线下的设备 ls /sys/devices/platform/*spi*/spi_master/spi*/spi*.* # 3. 快速查看所有SPI设备 ls /sys/bus/spi/devices/ # 4. 查看某个SPI设备的详细信息以spi0.0为例 cat /sys/bus/spi/devices/spi0.0/uevent cat /sys/bus/spi/devices/spi0.0/modaliasi2c spi这些是真实总线platform是虚拟总线为啥也放在platform下不是对应不上吗这问题问到Linux 设备模型最精髓的地方了你直觉完全没错I2C、SPI 是真实硬件总线platform 是虚拟总线但它们确实就应该放在/sys/devices/platform/下面一点都不矛盾。我用最清晰、最本质的方式给你讲透保证你以后再也不晕。一句话核心结论I2C/SPI 控制器本身是挂在 CPU 内部总线APB/AHB上的 “片上外设”Linux 对这类无法自动枚举的片上外设统一用 platform 总线管理。所以I2C/SPI 控制器 platform 设备挂在 I2C/SPI 上的传感器 I2C 设备 / SPI 设备这是两层结构不是同一层两层结构彻底讲清非常关键第一层I2C/SPI 控制器 是 platform 设备CPU 内部I2C 控制器SPI 控制器UARTPWMGPIOIR 红外控制器时钟控制器电源控制器它们全都 ** 直接连在 CPU 内部总线AHB/APB** 上。Linux 对这类内存映射寄存器有 reg 属性不能自动枚举不像 PCI/USB 插上去就能发现需要设备树描述统一归类为platform 设备所以它们在/sys/devices/platform/ff805000.i2c /sys/devices/platform/ff800000.spi第二层I2C/SPI 总线上的外设 才是真实 I2C/SPI 设备比如触摸屏陀螺仪温湿度传感器音频 codec红外传感器它们真的挂在 I2C/SPI 物理总线上所以它们的目录在/sys/devices/platform/ff805000.i2c/i2c-0/0-0048 ↑ 这才是真实 I2C 设备结构是platform虚拟 ↓ I2C 控制器platform 设备 ↓ i2c-0真实 I2C 总线 ↓ 0-0048真实 I2C 设备总线控制器 ≠ 总线本身控制器挂在哪层不影响总线本身类型为什么 Linux 要这么设计因为ARM / 嵌入式 SoC 内部外设太多全都接在 AHB/APB 上没有统一标准枚举方式只能靠设备树告诉内核 “这里有个控制器”Linux 为了统一管理发明了platform 虚拟总线专门收纳这类片上控制器。最终总结最精炼I2C/SPI 控制器是 platform 设备→ 所以在/sys/devices/platform/xxx.i2cI2C/SPI 总线上的传感器才是真实 I2C/SPI 设备→ 在i2c-0/0-0048或spi0.0platform 管的是 “控制器”不是 “总线”。I2C/SPI 管的是 “外设”不是 “控制器”。两层完全不冲突是标准 Linux 模型。每个目录里面一般有哪些文件重点进任意一个设备目录比如你会看到固定几样东西driver→ 软链接指向绑定的驱动有没有 probe 成功看这个of_node→ 设备树节点compatible、reg 都在这里uevent→ 设备信息主次设备号、驱动名power→ 电源管理subsystem→ 属于哪个子系统input→ 输入子系统设备节点说明该设备是输入设备比如红外遥控器、按键ls input/能看到event0等输入节点对应/dev/input/eventX用于调试输入上报驱动自己创建的属性文件如 status、enable 等devices/system/(系统核心设备)概述内容非外设的核心硬件system/cpu/CPU 核心、频率、缓存、在线状态online文件system/node/NUMA 节点system/clocksource/时钟源用途CPU 性能调试、电源管理、系统监控。devices/virtual/(虚拟 / 伪设备)概述内容非物理存在的逻辑设备virtual/net/lo本地回环网卡virtual/mem/内存设备null,zero,randomvirtual/block/loop[0-9]回环块设备用途网络配置、内存设备操作、挂载镜像文件。/sys/class按 “功能类” 归类设备同类设备放一起不管在哪条总线比如gpiopwmttynetblockinputpinctrl例/sys/class/gpio/ /sys/class/pwm/ /sys/class/input/相对好理解/sys/bus总线信息platform、i2c、spi、pci、usb每个总线下面有devicesdrivers你写 platform 驱动就在/sys/bus/platform/devices/ /sys/bus/platform/drivers/相对好理解/sys/bus/platform/下drivers和devices这两个目录是Linux platform 总线的核心入口专门用来管理平台设备和驱动的绑定关系是嵌入式驱动调试的「黄金入口」。一、核心定位两个目录的本质区别目录本质核心作用/sys/bus/platform/devices/所有 platform 设备的软链接集合按总线视角统一展示所有平台设备真身都在/sys/devices/platform/下/sys/bus/platform/drivers/所有 platform 驱动的目录集合展示所有已加载的平台驱动管理驱动与设备的绑定 / 解绑二、/sys/bus/platform/devices/详解1. 内容本质里面全是软链接100% 指向/sys/devices/platform/下的真实设备目录不占用额外空间。比如你截图里的红外设备会在这里生成一个同名软链接plaintext/sys/bus/platform/devices/ff634480.ir - ../../devices/platform/ff634480.ir/2. 核心用途快速遍历所有平台设备不用逐层翻/sys/devices/platform/直接ls就能看到所有平台设备验证设备是否被内核识别设备出现在这里 设备树加载成功、设备注册成功批量查看设备状态比如ls /sys/bus/platform/devices/*ir*快速定位红外设备3. 常用命令# 列出所有平台设备 ls /sys/bus/platform/devices/ # 快速查找红外相关设备 ls /sys/bus/platform/devices | grep -i ir # 查看设备的驱动绑定状态和真身目录完全一致 ls -l /sys/bus/platform/devices/ff634480.ir/driver三、/sys/bus/platform/drivers/详解1. 内容本质里面是每个已加载的 platform 驱动的独立目录每个目录对应一个内核驱动模块。比如你的红外驱动加载后会在这里生成/sys/bus/platform/drivers/ir_driver/2. 每个驱动目录里的核心文件进入任意驱动目录如ir_driver会看到标准文件bind/unbind可写文件手动绑定 / 解绑设备调试神器uevent驱动的环境变量信息module软链接指向/sys/module/ir_driver/驱动模块信息已绑定的设备软链接比如ff634480.ir说明该驱动已经和这个设备绑定成功3. 核心用途验证驱动是否加载成功驱动目录出现在这里 模块已加载、probe 函数执行手动绑定 / 解绑设备强制驱动和设备重新匹配调试驱动加载问题查看驱动绑定的所有设备ls /sys/bus/platform/drivers/ir_driver/直接看到所有绑定的设备/sys/module所有内核模块信息加载后的.ko都会在这里出现/sys/module/xxx_driver/能看到加载状态参数引用计数/sys/firmware固件 / 设备树相关/sys/firmware/devicetree/base/可以直接看当前内核用的设备树检查节点是否存在。注意设备树是按层级来的上层一般是目录然后逐级往下。/sys/kernel内核内部信息最重要的就是/sys/kernel/debug/ ← 你刚才问的 debugfs /sys/kernel/irq/debugfs参考Linux中驱动有问题如何排查一-CSDN博客那irq呢/sys/kernel/irq/是 Linux sysfs 下用于系统中断IRQ信息查询的标准化目录提供了比/proc/interrupts更结构化、更易于程序解析的中断状态视图。一、目录结构/sys/kernel/irq/下为 ** 每个有效的中断号IRQ** 创建一个子目录目录名即中断号。/sys/kernel/irq/ ├── 0/ ├── 1/ ├── 4/ ├── 32/ └── ... (其他中断号目录)二、每个中断目录如/sys/kernel/irq/32/下的核心文件1. actions内容逗号分隔的设备名列表表示该中断被哪些设备占用。示例eth0, ohci_hcd:usb1用途快速定位中断归属。2. chip_name内容中断控制器名称如GIC,IO-APIC,PCI-MSI。用途判断中断类型硬件总线 / 消息信号中断。3. hwirq内容硬件层面的原始中断号。用途内核中断号VIRQ与硬件中断号HWIRQ映射关系调试。4. type内容中断触发方式。edge边沿触发level电平触发用途驱动 / 硬件中断配置校验。5. wakeup内容yes或no。用途标识该中断能否唤醒休眠系统。6. per_cpu_count/子目录内含cpu0,cpu1... 等文件。内容每个文件记录对应 CPU 核心处理该中断的总次数。用途精确分析中断在多核间的分布定位中断负载不均问题。三、与/proc/irq/的核心区别/sys/kernel/irq/定位只读、结构化、机器友好的状态查询接口。内容chip_name,hwirq,per_cpu_count等底层硬件信息。/proc/irq/IRQ/定位可读写、面向用户的配置与控制接口。内容smp_affinity(CPU 亲和性),affinity_hint,spurious(伪中断计数)。四、常用操作示例# 1. 查看中断32的归属设备 cat /sys/kernel/irq/32/actions # 2. 查看中断32的控制器类型 cat /sys/kernel/irq/32/chip_name # 3. 查看中断32在各CPU上的计数 cat /sys/kernel/irq/32/per_cpu_count/cpu0 cat /sys/kernel/irq/32/per_cpu_count/cpu1总结/sys/kernel/irq/看中断硬件信息、统计。/proc/irq/改中断亲和性、开关。/sys/block/sys/block块设备的「快捷入口」1. 本质是什么/sys/block是所有块设备硬盘、U 盘、SD 卡、eMMC、loop 设备等的统一视图入口里面全是软链接指向/sys/devices/下对应设备的真实目录。2. 里面有什么每个子目录对应一个块设备比如/sys/block/ ├── sda/ # SATA硬盘 / U盘 ├── mmcblk0/ # eMMC / SD卡 ├── loop0/ # 回环设备 └── nvme0n1/ # NVMe固态硬盘每个目录里包含块设备的核心属性size设备总大小扇区数512 字节 / 扇区queue/IO 队列参数调度器、队列深度、缓存等dev主次设备号major:minordevice/软链接指向/sys/devices/下的真实硬件控制器目录3. 核心用途快速查看所有块设备不用逐层翻/sys/devices/直接ls /sys/block就能看到所有存储设备查看块设备参数比如cat /sys/block/sda/size算硬盘容量cat /sys/block/sda/queue/scheduler查看 IO 调度器调试存储性能修改队列参数、调整缓存、排查 IO 问题区分真实硬件 vs 虚拟设备sda/mmcblk0是真实硬件loop0是虚拟回环设备4. 常用命令# 列出所有块设备 ls /sys/block/ # 查看sda的总容量扇区数 × 512字节 cat /sys/block/sda/size # 查看当前IO调度器 cat /sys/block/sda/queue/scheduler # 查看设备主次设备号 cat /sys/block/sda/dev/sys/dev/sys/dev设备号的「快捷入口」1. 本质是什么/sys/dev是按「主次设备号major:minor」索引的设备视图入口里面全是软链接指向/sys/devices/下对应设备的真实目录。2. 里面有什么按设备号分两级目录/sys/dev/ ├── block/ # 块设备号索引 │ └── 8:0/ # 对应sdamajor 8, minor 0 └── char/ # 字符设备号索引 └── 1:3/ # 对应/dev/nullmajor 1, minor 3比如/sys/dev/block/8:0就是/sys/block/sda的软链接指向同一个真实设备目录。3. 核心用途通过设备号快速定位设备已知major:minor直接找到对应设备统一管理块 / 字符设备块设备在block/子目录字符设备在char/子目录调试设备节点排查/dev下设备文件与真实硬件的对应关系udev 规则开发udev 会通过这个目录匹配设备号创建设备文件4. 常用命令# 查看sda对应的设备号 cat /sys/block/sda/dev # 输出8:0 # 通过设备号反向找设备 ls -l /sys/dev/block/8:0 # 输出../../devices/pci0000:00/14.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/block/sda/sys 到底怎么用驱动开发时/sys 到底怎么用最实用部分我给你列驱动开发天天用的操作1. 看驱动有没有匹配成功ls /sys/bus/platform/drivers/你的驱动名/里面有设备名 匹配成功2. 看设备是否存在ls /sys/devices/platform/你的设备名3. 操作 GPIO不用写应用直接调试cd /sys/class/gpio echo 100 export # 导出GPIO echo out direction # 设为输出 echo 1 value # 输出高电平4. 看中断被触发了多少次cat /sys/kernel/irq/45/irq_count5. 看设备树节点是否生效ls /sys/firmware/devicetree/base/irxxx6. 看引脚配置pinctrlcat /sys/kernel/debug/pinctrl/.../pinconf-pins7. 看时钟是否打开cat /sys/kernel/debug/clk/clk_summary8. 看设备是否被正确绑定cat /sys/devices/platform/xxx/driver_override四、/sys 对驱动开发的意义超级重要1. 驱动状态可视化probe 成没成匹配没匹配时钟开没开引脚对不对不用读 dmesg 大海捞针直接看 /sys。2. 不用写应用就能调试硬件GPIO、PWM、LED、REGULATOR 都能直接 echo/cat 调试。3. 快速定位问题设备没出现 → 设备树或设备注册问题驱动目录空 → 匹配失败compatible 错gpio 导出失败 → 被占用或引脚复用错4. 驱动可以自己在 /sys 创建设备属性让应用层读状态、设参数device_create_file(dev, dev_attr_xxx);应用就能cat /sys/devices/.../xxx五、最简单总结你记住这个就够/sys 就是内核的 “设备浏览器”。/sys/class→ 按功能分类/sys/devices→ 真实硬件结构/sys/bus→ 总线与驱动匹配/sys/module→ 模块信息/sys/kernel/debug→ 调试状态驱动开发时看设备、看驱动、看引脚、看时钟、调 GPIO全部靠 /sys。

更多文章