news 2026/9/30 18:04:53

lspci与Kernel modules:从PCI设备到驱动匹配的完整链路解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
lspci与Kernel modules:从PCI设备到驱动匹配的完整链路解析

搞Linux排查硬件,lspci 几乎是人手一条的命令。插上新卡不识别、开机没显示、驱动装上又掉,凡是跟 PCI 设备沾边的问题,第一反应都是先lspci看一遍。输出里的“Kernel modules”这一列尤其关键,它直接告诉你内核里有哪些驱动模块可以接管这台设备。但很多人从来没想过:这一列信息到底是从哪里来的,是 lspci 自己读出来的,还是内核告诉它的?为什么设备明明插的是 AMD 的卡,执行lspci | grep -i amd却搜不到任何内容?这篇文章就围绕 lspci 和 Kernel modules 这条信息链路,把数据源头、解析逻辑、匹配机制和故障排查完整过一遍。适合刚接触 Linux 驱动排查的运维、嵌入式开发者,也适合那些想知道“系统到底怎么知道该加载哪个驱动”的进阶玩家。

1. lspci 与 Kernel modules 列:先搞清楚它到底在显示什么

1.1 Kernel modules 列不等于“当前正在用的驱动”

用lspci -k查看设备时,会看到两行容易混淆的内容:Kernel driver in use和Kernel modules。我见过不少朋友把这两行当成一回事,结果排查时走了不少弯路。严格来说,这两行的含义完全不同:Kernel driver in use指的是这台 PCI 设备当前实际绑定的驱动,代表设备已经被某个驱动接管,能在lsmod里查到对应模块;而Kernel modules则是内核认为“有可能”匹配这台设备的模块列表,它们只是候选,未必加载了。

举个常见的例子。一台同时有 Intel 核显和 NVIDIA 独立显卡的机器,lspci -k会看到核显的Kernel driver in use是 i915,而Kernel modules里列出 i915 和 nouveau;独显的Kernel driver in use是 nvidia,但Kernel modules里可能同时有 nvidia 和 nouveau。这里 nouveau 就是纯候选,系统并没有加载它。这个区分非常重要,很多人看到Kernel modules里有 nouveau,就觉得驱动冲突了,其实只要Kernel driver in use是 nvidia,设备就是被正常接管的,没有冲突。

1.2 默认输出里根本看不到这一列

再强调一个基础事实:lspci的默认输出只有一行设备描述,比如VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] ...,根本不会出现Kernel modules字样。必须加上-k或-v参数,这一列才会显示出来。

-k是最轻量的方式,只多显示驱动关联信息;-v更详细,会显示设备的各项能力、中断、资源等;-nn则能把 vendor ID 和 device ID 以数字形式打印出来,比如1002:73bf。一般排查时我习惯直接lspci -nnk一起上,一次把 ID、驱动、模块全看清。很多网上教程只写lspci或lspci -v,新手照做之后看不到Kernel modules列,还以为自己系统有问题,其实只是参数没给够。

1.3 为什么系统要把“候选”和“当前”分开

这套设计不是刻意复杂,而是 Linux 内核模块自动装载机制决定的。设备出现时,内核设备核心会为它生成一个 modalias 标识;udev/kmod 拿到这个标识后,去模块别名的数据库里匹配,决定加载哪些模块。但“加载哪个模块”只是尝试,真正的绑定还要看驱动的 probe 是不是成功。候选驱动可以有很多个,实际绑定只能有一个,所以 lspci 用两行来分别显示这两个阶段的状态。

换句话说,Kernel modules是设备驱动匹配的第一道筛子,Kernel driver in use是最后的结果。理解了这个关系,后面看数据来源就顺理成章了。

2. Kernel modules 的信息从哪来:一条从硬件到模块的完整链路

2.1 一切从 PCI 配置空间开始

每一块 PCI 设备都有一段可以被系统读取的配置空间,空间里固定位置存着 vendor ID、device ID、class code、子系统 ID 等信息。Linux 内核在系统启动和热插拔时扫描 PCI 总线,把这些信息解析出来,然后暴露到 sysfs,也就是/sys/bus/pci/devices/目录下。

拿一台 AMD 显卡举例,设备目录通常是/sys/bus/pci/devices/0000:01:00.0,里面有一堆小文件。执行cat /sys/bus/pci/devices/0000:01:00.0/vendor,输出是0x1002,这是 AMD 的 vendor ID;device文件输出设备 ID;class文件是设备类别;modalias文件则是拼接好的完整 ID 串。如果用生活化类比,vendor ID 相当于省份,device ID 是城市,subsystem ID 是街道,class code 则是职业。lspci 所有的显示内容,本质上都是在拿这套数字 ID 做翻译,它本身并不去碰硬件。

2.2 pci.ids:把数字 ID 翻译成厂商名的字典

lspci 显示Advanced Micro Devices, Inc. [AMD/ATI]而不是0x1002,靠的是一个文本数据库 pci.ids。它通常在/usr/share/hwdata/pci.ids,部分发行版放在/usr/share/misc/pci.ids,不装 hwdata 包的最小系统则完全没有这个文件。

文件格式不复杂,有注释行,有 vendor 行,有缩进的设备行,还有再缩进的子系统行。lspci 启动时加载它,按 ID 查表翻译。文件缺失或过旧,输出就只剩 class 描述和数字 ID。管理数据库用update-pciids命令从网络获取最新版,或者直接安装 hwdata 包。这里要注意:pci.ids 只是给人看的字典,它不参与任何驱动匹配,驱动能不能用跟这个文件一点关系都没有。

2.3 modalias 和 modules.alias:匹配的核心

lspci 的Kernel modules列,来源其实不在 pci.ids 里,真正的匹配发生在设备和模块之间,核心是两个文件:设备侧的 modalias,和模块侧的 modules.alias。

设备侧,cat /sys/bus/pci/devices/0000:01:00.0/modalias,会打印类似pci:v00001002d000073bfsv00001002sd0000...这样一串。它把 vendor、device、子系统 vendor、子系统 device、class 等信息按固定格式编码,v 后面是 vendor,d 后面是 device,sv/sd 是子系统,bc/sc 是分类码。

模块侧,驱动源码里用MODULE_DEVICE_TABLE(pci, xxx_ids)声明支持的 ID 表。编译安装模块时,depmod 扫描所有内核模块,从中提取这些 ID 表,生成/lib/modules/$(uname -r)/modules.alias和modules.alias.bin。里面的每一行都是一个“模块别名”,形如alias pci:v00001002d000073bfsv* sd* bc* sc* i* amdgpu。运行lspci -k时,lspci 通过 libkmod 把设备的 modalias 和 modules.alias.bin 里的所有规则做匹配,凡是匹配到的模块名,全部收进Kernel modules列。这一段链路才是“Kernel modules 信息来源”的核心答案。

2.4 整条链路一图流

设备 PCI 配置空间 → 内核 PCI 枚举 → sysfs 暴露 vendor/device/class/modalias → pci.ids 翻译成厂商名 → lspci 显示设备描述 → libkmod 用 modalias 匹配 modules.alias → 列出候选内核模块。

所以下次再有人问“lspci 怎么知道该列哪些模块”,答案不是“它猜的”,也不是“它读驱动的”,而是它走了整整一条从硬件配置空间到内核模块别名的数据链路。了解这条链路,排查驱动问题会轻松很多。

3. 复盘“lspci | grep -i amd 无反应”:为什么明明有 AMD 设备却搜不到

3.1 最常见的原因:默认输出里根本没有你想搜的字段

先说一个我遇到最多的场景。很多人听说lspci | grep能过滤设备,就直接执行lspci | grep -i amd,想找到 AMD 显卡对应的驱动线索。但默认的 lspci 输出里只有一行设备描述,既没有Kernel modules列,也不一定包含你想找的模块名。你要是想搜的是amdgpu这样的模块名,默认输出里当然没有;就算设备确实是 AMD 的,如果 pci.ids 数据库里缺这条记录,输出可能连“AMD”字样都没有。

所以遇到“没反应”,先分清你搜的到底是厂商名(AMD)还是模块名(amdgpu),再决定要不要加-k。grep -i amd想看到结果,前提是 lspci 输出的文本里真的有“AMD”这三个字母;想看到驱动模块,就得用lspci -k | grep -i amd或者直接搜模块名。

3.2 pci.ids 缺失:连厂商名都没了

最小化安装、容器环境、精简服务器上,hwdata 或 pciutils 的数据文件很可能没装。此时 lspci 的输出变成VGA compatible controller加一堆编号,完全没有Advanced Micro Devices, Inc.。这种情况下,grep -i amd搜不到再正常不过。

验证方法很简单:ls /usr/share/hwdata/pci.ids看文件在不在,或者跑lspci -nn看有没有显示数字 ID。解决就是安装 hwdata 包,或运行update-pciids更新数据库。老硬件如果设备 ID 较新,数据库过旧时厂商名也会缺失,更新一下往往就恢复了。

3.3 alias 和机器可读模式的干扰

还有一种隐藏坑:很多人在~/.bashrc里设了alias lspci='lspci -nn'。这样表面上设备输出的是1002:73bf,没有“AMD”字样,grep -i amd自然为空。看起来“无反应”,其实只是 lspci 在你的环境里被改了默认参数。检查type lspci就能看到你是不是被 alias 坑了。

另外,管道场景下 lspci 的输出格式会变化,尤其是lspci -mm机器可读模式,每个字段用引号包裹、用换行符分隔,和终端看到的表格完全不一样。在这种模式下 grep 搜索的关键词、期望的输出结构都要重新设计,直接拿平时的 grep 习惯套上去,很容易出现“明明有 AMD 设备却搜不到”的错觉。

3.4 设备 ID 不在数据库里,厂商名匹配但型号缺失

最后一种典型情况:设备能显示Advanced Micro Devices, Inc.,但设备描述只有VGA compatible controller,没有Radeon RX等具体型号。这是因为 pci.ids 里没收录这个 device ID,或者数据库太旧。此时grep -i amd能匹配到 vendor 行,但grep -i radeon匹配不到,很多人会误以为“显卡没识别”。用lspci -nn拿到数字 ID,去 pci.ids 或网上查真实型号,再考虑更新数据库,就清楚了。

4. 实操手册:把 Kernel modules 的来源一条条查出来

4.1 设备侧:从 sysfs 读取原始 ID

lspci 显示的是翻译结果,sysfs 里的是原始值。排查时我喜欢直接看 sysfs,它不受 pci.ids 数据库影响:

for d in /sys/bus/pci/devices/*/; do echo "== $d" cat "$d/vendor" "$d/device" "$d/class" cat "$d/modalias" done

这样能看到所有 PCI 设备的 vendor、device 和完整 modalias。对比lspci -nn的输出,能确认 lspci 是否因为数据库缺失做出了错误的翻译。如果 sysfs 里的 vendor 是 0x1002,但 lspci 没显示 AMD,那就是字典的问题,不是硬件问题。

4.2 模块侧:用 modinfo 验证 alias

modinfo -F alias可以看某个模块导出的所有别名。比如modinfo -F alias amdgpu会打印一长串pci:v00001002d...格式的条目。重点关注通配符,d0000*表示匹配该 vendor 下所有设备 ID。一个模块能匹配多个设备,正是因为这些带通配符的别名。

手工验证匹配也很简单:把设备 modalias 字符串和模块 alias 做对照。modules.alias 里的星号就是通配符,匹配成功就是候选模块。比如设备 modalias 是pci:v00001002d000073bf,模块 alias 是pci:v00001002d000073bf*,那就能对上,lspci 的Kernel modules列就会列出这个模块。

4.3 交叉验证:lspci -k 结果和 lsmod 对比

lspci -k 列出了所有“候选”,lsmod 列出了“当前已加载”。两者做差集,能发现没被加载的驱动:

lspci -k | grep -A2 -i vga lsmod | grep -i amdgpu

如果设备Kernel driver in use为空、Kernel modules里有 amdgpu 但 lsmod 里没有,说明 amdgpu 作为候选存在,但没被自动加载,问题出在模块自动加载环节,而不是驱动不支持。反过来,如果Kernel modules里根本没有 amdgpu,问题就出在 depmod 缓存或模块本身。

4.4 数据库和模块别名的刷新姿势

更新 pci.ids 用update-pciids;更新模块别名缓存用depmod -a。如果你手动放了一个新模块到/lib/modules/$(uname -r)/extra/,不跑depmod -a,lspci 的Kernel modules列不会出现它的名字。这个顺序很多人搞反,结果新驱动明明装了,lspci 却看不到,于是开始怀疑模块本身有问题。其实只是缓存没刷新。

5. 常见问题与排查技巧实录

5.1 Kernel modules 列为空怎么办

大概三类原因:设备 ID 确实没有模块支持;内核模块没安装;depmod 缓存没生成。排查顺序是先看 sysfs 的 modalias,再用 modinfo 在/lib/modules里找匹配记录,最后确认 depmod 是否跑过。

cat /sys/bus/pci/devices/0000:01:00.0/modalias grep "$(cat /sys/bus/pci/devices/0000:01:00.0/modalias)" /lib/modules/$(uname -r)/modules.alias

第二条命令如果没有任何输出,说明在现有模块集里确实没有匹配项,要么装驱动,要么换内核,而不是在 lspci 上找问题。

5.2 设备显示 unknown 或空 ID

旧硬件比较常见,设备 ID 在最新 pci.ids 里也查不到,lspci 只能显示unknown device。处理建议:先更新数据库,再用lspci -nn记录数字 ID 上网查询,最后可以把完整输出-o参数保存到文件留档。这种问题不影响驱动加载,因为驱动匹配不依赖 pci.ids,只是显示上不好看。

5.3 新增网卡或显卡后,模块永远是候选但不加载

这不是 lspci 的问题,是 kmod 自动加载没触发。检查 udev 规则、modprobe.conf、模块是否在/lib/modules/$(uname -r)/下。要手动验证就modprobe一下,能加载成功就说明模块本身没问题,问题在自动加载策略。

5.4 排查速查表

现象可能原因排查命令解决方向
lspci 无 Kernel modules 列没加 -k 或 -vlspci -k正确加参数
grep -i amd 搜不到pci.ids 缺失ls /usr/share/hwdata/pci.ids安装 hwdata、update-pciids
只显示数字 ID数据库过旧lspci -nnupdate-pciids
Kernel modules 为空depmod 缓存未生成grep modalias /lib/modules/.../modules.aliasdepmod -a
候选模块不加载自动加载没触发lsmod; modprobe 模块名检查 udev 规则、modprobe.d

5.5 一点个人习惯

踩过几次坑之后,我的习惯是:真正排查驱动问题时,第一件事不是看 lspci,而是cat /sys/bus/pci/devices/0000:01:00.0/modalias,它把该看的都编码进去了。搜索时用grep -E "AMD|amdgpu|1002"多路搜索,不把鸡蛋放在一个关键词上;写脚本尽量按 vendor ID 比较,不依赖文本翻译。这样能避免 pci.ids 缺失这种表层问题干扰判断。这套方法帮我解决了不少“驱动明明在却找不到设备”的怪问题,希望对你有用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 18:04:41

用大模型与事件流自动化项目复盘:三段式Prompt实战

2. 核心细节解析与实操要点2.1 数据输入:把散落的信息变成结构化事件流复盘这件事,最难的往往不是分析,而是"先把当时发生了什么拼出来"。项目日志、聊天记录、代码提交、会议纪要,散落在不同系统里,人脑回忆…

作者头像 李华
网站建设 2026/9/30 18:02:13

大模型GPU推理优化:TensorRT与vLLM部署全链路实践指南

1. 项目概述:Model-Optimizer不是工具名,而是一类工程实践的统称“Model-Optimizer”这个标题乍看像某个开源项目或商业软件的名字,但结合NVIDIA、TensorRT-LLM、vLLM、PT文件转换TensorRT等热搜词,它实际指向的是大模型推理服务落…

作者头像 李华
网站建设 2026/9/30 17:55:51

客户端加密实战:避开密钥管理与算法模式的五大陷阱

你有没有见过那种号称“加密了”的客户端,结果被人一抓一个准,数据库拖出来明文直接裸奔?我见过太多次了。不少团队把“客户端加密”当成万能保险,以为数据在用户设备上转了一圈密码学算法就高枕无忧了。实际做下来,这…

作者头像 李华
网站建设 2026/9/30 17:55:51

Vue+PHP+UniApp实战:宿舍打卡失物招领系统全解析

先说结论:如果你正准备做一套宿舍管理类的小程序,或者正卡在“前端小程序 后端接口 管理后台”这套组合的坑里,这篇文章应该能帮你省下不少时间。我以 vue-phpuniapp 小程序的学生宿舍打卡失物招领管理系统(工程代号 a97r2&…

作者头像 李华
网站建设 2026/9/30 17:52:15

开源AI文档阅读器:基于RAG的私有化知识库问答系统实践

上次发了个动态说要做个开源的 AI 文档阅读器,后台私信和群里直接炸了,天天有人催更。今天总算把代码整理出来,可以讲点干货了。这个项目不花哨,核心就一件事:把 PDF、Word、TXT、Markdown 丢进去,系统自动…

作者头像 李华