【经验分享】面试必问的 PCIe 拓扑与 Bus 分配,今天用一张图给你讲得明明白白!

近期有用户在使用我们的PCIe 6.0 switch卡连接Nvidia Mellanox CX系列网卡的时候问到一个关于PCIe 拓扑树(topology tree)显示的问题。我们知道,在 PCIe 系统和服务器硬件运维中, lspci 输出的树状图(Topology)是排查设备链路、拓扑结构和 Bus 号分配问题的核心工具。今天就来结合我们用户的这个实际问题,来详细拆解如何阅读 PCIe Tree、解答关于 Bus 号范围(Upstream/Downstream)看起来好像不一致的疑问,并盘点全球工程师最常用的 lspci 参数与经典实战案例。
一、 图解:如何阅读 lspci-t 拓扑树?
首先,我们用一个标准的、干净的 lspci-t 拓扑图范本来做教学:

拓扑图的基本阅读逻辑:
- 左侧根节点
-[0000:80]-:表示 PCIe Domain : Root Bus (根总线)。这里代表 Domain 为 0000,Root Bus 号是80。通常对应 CPU 内部的 Host Bridge。 - 分支节点
+-04.1:代表在 Bus 80 上的 Device 04, Function 1(即80:04.1)。这是一个 Root Port(根端口),本质上是一个 PCI-to-PCI 桥。 - 括号区间
-[81-94]:紧跟在桥设备后面的方括号,表示该桥所能控制/预留的子总线范围(Subordinate Bus Range)。 - 横线连接
----00.0:表示下一级总线上的设备。例如-[81-94]----00.0意味着,在进入次级总线后,遇到的第一个设备是81:00.0。
二、 核心疑问:为什么 Upstream 和 Downstream 的 Bus 号范围不一致?
在随附的截图中,有两处画红线的 Bus 范围区间:
- 根端口下挂的范围是:
-[81-94] - 后面紧跟的交换芯片/子桥下挂的范围是:
-[82-93]
1. 为什么它们不一致?
这属于非常经典的 PCIe 桥的 Bus 资源分配与嵌套(Nested Bridges)。
在 PCIe 规范中,每一个 PCI-to-PCI Bridge(包括 Root Port, Switch Upstream Port, Switch Downstream Port)在配置空间里都有三个关于 Bus 的寄存器:
- Primary Bus Number:桥本身所处的上级总线号。
- Secondary Bus Number:桥直接导出的下一级总线号。
- Subordinate Bus Number:该桥下方所能延伸达到的最大(最后一级)总线号。
2. 对照原图的拓扑级联关系拆解:
- 第一层(Root Port)
80:04.1: - 它直接导出的下一级 Bus 是 81。
- 它能管辖的整个庞大子系统的最大范围是 81 到 94(共 20 个 Bus 号空间)。
- 第二层(PCIe Switch 的 Upstream Port)
81:00.0: - 它是由 Bus 81 上的设备导出的。
- 它自身的次级 Bus 是 82。
- 重点: 它并没有把上级给的 94 全吞掉,它向上汇报自己管辖的最大范围是 82 到 93。
- 第三层(PCIe Switch 的 Downstream Ports):
- 在
82-93的内部,Switch 拆出了非常多的下游端口(Downstream Ports),例如00.0,01.0,02.0直到10.0。 - 其中的
00.0端口直接分配了 Bus 83 给网卡(Mellanox ConnectX-6 Dx),而网卡拥有两个 Function(00.0和00.1)。 - 剩下的
01.0分配了 Bus 84,02.0分配了 Bus 85……以此类推,直到10.0分配了 Bus 93。
3. 为什么空出了 Bus 94?
你会发现 Root Port 批了 81-94,但底下的 Switch 只用了 82-93,94 消失了。
这是因为 BIOS/系统内核在进行 PCIe 热插拔预留(Hotplug Reservation)。系统为了防止用户以后在这个 Root Port 附近插入新的扩展卡或切分设备,故意在最外层(Root Port)多留了一个 94 号总线。如果未来有新硬件插入,可以直接将 94 分配给新硬件,而不需要重新打乱、刷新整个 81-93 已经分配好的现有拓扑结构。
三、 全球最常用 lspci 命令与实战案例
以下是根据全球系统工程师和内核开发者的使用频度,整理出的最常用 lspci 参数及其实战解决的问题:
| 常用命令组合 | 全球频度 | 核心作用描述 |
|---|---|---|
lspci |
⭐⭐⭐⭐⭐ |
快速列出所有 PCI 设备简要信息。 |
lspci-tv |
⭐⭐⭐⭐☆ |
带有设备详细名称的树状拓扑图显示。 |
lspci-vvv |
⭐⭐⭐⭐⭐ |
打印极其详细的硬件底层配置空间及链路状态。 |
lspci-k |
⭐⭐⭐⭐☆ |
显示每个 PCI 设备当前绑定的内核驱动和可选模块。 |
lspci-nn |
⭐⭐⭐⭐☆ |
同时显示设备的文字名称和数字化的 Vendor ID / Device ID。 |
lspci-s<BDF> |
⭐⭐⭐⭐⭐ |
精准过滤并只查看指定 BDF 地址的设备。 |
经典实战案例佐证
案例一:排查设备是否降速(物理链路劣化)
- 命令:
lspci-vvv-s83:00.0|grep-E"LnkCap|LnkSta" - 为什么要用:
当你在测试 Mellanox 网卡或 NVMe 盘时,发现性能死活跑不满(例如原本 100G 的网卡只能跑 50G)。
- 解决什么问题:
-vvv可以 dump 出 PCIe 能力寄存器。LnkCap(Link Capability)代表硬件设计最高支持的能力(如Speed16GT/s,Widthx16,即 PCIe 4.0 x16)。而LnkSta(Link Status)代表当前实际运行的状态。如果实际状态显示Speed8GT/s,Widthx8,说明硬件可能由于金手指脏污、机箱震动或信号干扰,在物理层发生了解宽和降速。使用该命令能一秒定位物理链路故障。
案例二:硬件无法识别,需要找驱动或提报 Bug
- 命令:
lspci-nn|grep-i mellanox - 为什么要用:
当系统里装了一块新网卡或加速卡,操作系统无法识别它(显示为
Unknowndevice),或者你在写自动化脚本、需要精确匹配芯片型号。 - 解决什么问题:
标准的
lspci只输出人能看懂的文本(依赖本地的pci.ids数据库)。如果数据库没更新,就看不到名字。加上-nn后,会强制输出十六进制的数字,例如[15b3:101d](15b3 是 Mellanox 厂商 ID,101d 是设备 ID)。有了这个绝对唯一的数字 ID,工程师可以直接去谷歌查到该芯片的官方型号,或者直接写进内核驱动的match_table里去加载驱动。
案例三:排查网卡、GPU 到底用的是哪个驱动
- 命令:
lspci-k-s83:00.0 - 为什么要用:
在配置网络 DPDK 高性能转发或者安装 NVIDIA/AMD 显卡驱动时,经常需要确认当前设备是被内核自带的开源驱动(如
nouveau、mlx5_core)接管,还是被用户态驱动(如vfio-pci)接管。 - 解决什么问题:
使用
-k参数会明确输出两行:Kerneldriverinuse:mlx5_core(当前正在生效的驱动)Kernelmodules:mlx5_core(系统里可供选择的驱动模块)这能让装驱动、切驱动的运维过程变得极其透明,防止“驱动没装上”或“驱动冲突”导致的各种玄学罢工。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)