我对 PCI 总线/设备/功能枚举感到困惑。查看PCI 配置的 Wikipedia 页面,我看到对于给定的总线,主机将使用函数 0 请求所有设备的供应商 ID 和设备 ID。如果返回所有 0xFF,则没有设备存在,枚举继续进行。如果找到了有效的设备 ID 和供应商 ID,则那里有一个 PCI 单元,并且将对其进行枚举。我不确定 bus.device.function 中的设备是如何确定的。
例如,假设我有一个 CPU,它带有一个 PCI 总线和一个连接到它的 PCI 外围设备。我知道 CPU 将查看总线 0(默认情况下),并将检查查看功能 0 的所有设备编号。如何确定外围设备的设备编号?
在最初的 PCI 框架(“Conventional PCI”)和 PCI-X 中,设备对应于“插槽”,每个插槽都有自己的连接器连接到同一并行总线。每个插槽都有一个唯一的 ID 引脚,在枚举期间被声明。枚举本质上是在询问(对于每个插槽):“嘿,这个插槽中有什么东西吗?” 设备响应此信号,通过将数据驱动到总线上来进行响应。缺乏响应意味着没有设备。
一个设备也可以是一个“桥”,这意味着它形成了一个从属总线。该总线将有一个单独的 ID(从上游分配),并有自己的一组独立枚举的插槽。
PCI-Express (PCIe) 则完全不同。PCIe 并不是真正的总线——就像设备之间共享的资源一样;相反,每个设备都有自己单独的点对点串行连接到其上游设备(以及任何下游设备——如果它有下游设备,这意味着它也起到了桥接器的作用)。将 PCIe 视为 LAN。每个网桥类似于一个交换机,它有一堆端口连接到其他设备。其他设备可能是终端设备,也可能是其他交换机(即 PCIe 桥接器)。
PCIe 的设计方式使其概念框架和寻址(以及因此提供给软件的行为)与 PCI 和 PCI-X 兼容。虽然实现是完全不同的。例如,在枚举设备时,由于它是点对点的,因此需要在枚举中的每个点确定的唯一问题是“那里有什么?” 由于每个设备都有自己独立的一组电线,因此设备 ID 基本上都是硬编码的(因此每个网桥,包括顶级“根复合体”,都会告诉每个设备其设备 ID 是什么)。
在所有情况下,总线/设备/功能的“功能”部分都在外围设备内严格处理。例如,双端口 NIC 控制器通常具有两个功能,每个端口一个。它们可以独立配置和操作,但从 CPU 到功能的数据路径对于两者是相同的。