许多用户在通过lspci命令查看显卡或网卡时,常会遇到一个现象:如果不加sudo直接运行,输出的设备信息会不完整,厂商名称、驱动状态等关键字段可能显示为[device]或直接空白。这背后是Linux内核的PCI权限管理机制在起作用。
简单来说,普通用户的进程默认只能访问/sys/bus/pci/devices目录下的简化设备树信息。而厂商ID、设备ID、内存地址范围(BAR)、中断号(IRQ)等关键硬件配置,都保存在内核的PCI配置空间中,对这些数据的读取需要更高的权限。因此,只有通过sudo lspci命令才能获取完整的底层硬件细节。此外,一些较新的Linux发行版(例如Ubuntu 22.04及以上版本)默认禁用了旧的/proc/bus/pci接口,这可能导致即使使用了sudo,某些深度调试选项(如-x或-vv)也会报错“Cannot read configuration space”。如果仅需在脚本中识别设备型号,可以使用lspci -mm命令,它以机器可读的格式输出,对权限要求相对宽松。

为何普通用户运行lspci看不到显卡或网卡的完整信息?
根本原因在于权限控制。设备的厂商名、驱动状态、内存地址等关键信息,都受到内核PCI配置空间的访问限制。普通用户默认只能读取/sys/bus/pci/devices路径下的基础设备树结构,获取的是简化数据。因此,没有sudo权限时,许多字段会显示不全。
- 只有执行
sudo lspci才能访问完整的PCI配置空间,从而获得设备ID、BAR地址、中断号等底层信息。 - 部分发行版(例如 Ubuntu 22.04及以上)默认禁用了/proc/bus/pci接口,此时即便使用
sudo,-x或-vv参数也可能出现报错:Cannot read configuration space。 - 如果仅需识别设备型号,
lspci -mm(机器可读格式)对权限要求较低,非常适合在脚本中调用。
lspci -v与lspci -vv的实际差异是什么?
这两个选项的详细程度存在本质区别。-v(verbose)输出的信息已经足够实用,涵盖了驱动模块名、IRQ中断号、内存/IO地址范围以及PCI Capabilities等运维和调试的常用字段。而-vv(very verbose)则更进一步,它将展开PCIe的扩展能力寄存器、ACS(访问控制服务)控制位、AER(高级错误报告)配置等深度调试内容,这些信息在日常问题排查中很少用到。
lspci -v可以显示Kernel driver in use: iwlwifi这样的关键信息,足以判断驱动是否已加载。lspci -vv可能展示Root Port ACS Capability: Src Valid, Trans Blind, End Blind, Rcvr Redir,这类信息仅在排查PCIe设备直通(如KVM虚拟机透传GPU)时才需要关注。- 这两个选项都依赖内核开启CONFIG_PCI_DEBUG,部分精简内核(例如某些容器宿主机)在编译时可能未启用该选项,导致
-vv的输出异常简略。
如何快速定位NVIDIA显卡对应的内核模块和设备ID?
最直接的方法是组合使用-k和-nn参数。-k用于显示内核驱动信息,-nn则直接输出设备的厂商ID和设备ID,便于查阅官方文档或匹配驱动白名单。
- 执行
sudo lspci -k -nn | grep -A 3 -i nvidia,输出中会同时显示类似01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP104 [GeForce GTX 1080] [10de:1b80] (rev a1)以及Kernel modules: nvidiafb, nouveau, nvidia的行。 - 需注意区分两个字段:
Kernel driver in use:表示当前实际工作的模块(例如nvidia),而Kernel modules:列出的是内核检测到的、所有可能支持该设备的模块。 - 如果
Kernel driver in use显示为空,则表明设备未被任何模块绑定。此时应检查nvidia.ko是否已加载(使用lsmod | grep nvidia),或者是否存在驱动冲突(例如nouveau开源驱动未被加入黑名单)。
使用lspci -s指定槽位时容易出错的地址格式
使用lspci -s按地址筛选设备时,经常遇到的陷阱是地址格式。PCI地址遵循domain:bus:slot.function的格式,但很多人容易忽略slot(插槽)和function(功能)的十六进制解析规则——它们并非简单的十进制数字,而是根据PCI规范定义的5位slot加3位function编码。
- 例如,地址
0000:01:00.0中,0000是domain,01是十六进制bus号,00是十六进制slot号,.0是function号。如果只写lspci -s 01:00.0,在存在多个根复合体(root complex)的系统中(例如某些服务器),可能会匹配到错误的PCI总线。 - 稳妥的写法是带上domain部分:使用
lspci -s 0000:01:00.0。这样可以避免在双路服务器或使用了PCIe交换芯片的环境中发生误匹配。 - 此外,function号不一定是
.0。有些多功能设备(如某些NVMe SSD)可能拥有多个function(例如.0,.1)。如果漏掉.0后缀,命令可能静默失败(无任何输出)。
最后,有一个非常重要的细节经常被忽视:lspci的输出并非实时刷新。它读取的是内核在启动时枚举的PCI设备快照。这意味着,如果你热插拔了一个设备(例如通过Thunderbolt接口外接了一块GPU),直接运行lspci是看不到新设备的。你需要先通知内核重新扫描PCI总线:echo 1 > /sys/bus/pci/rescan,然后再执行lspci,新设备才会出现在列表中。
