- 扫描 PCI 总线,识别 PCI 总线上的所有设备。
- 对于连接在 PCI 总线上的所有 PCI 桥进行总线编号。
- 对于连接在 PCI 总线上的所有 PCI 设备和 PCI 桥进行 Memory/IO 访问空间的配置。
这部分代码在 pciauto_bus_scan() 函数中(位于 arch/ppc/syslib/pci_auto.c 中)。
识别 PCI 总线上的设备
PCI 总线扫描的原理是从总线 0 扫描到总线 255,对于每条总线,系统都会扫描所有(总线号,设备号,功能号),通过 Configuration 方式读出每个设备的 Device ID 和 Vendor ID 寄存器,如果这两个寄存器的值是个有效值(非 0xFFFF),则说明当前设备是个有效的 PCI 设备/桥。进而再读取该设备的 Header Type 寄存器,如果该寄存器为 1,则表示当前设备是 PCI 桥,否则是 PCI 设备。
对所有 PCI 总线进行编号
PCI 桥如何知道它所连接的 PCI 总线情况呢?这就需要对 PCI 桥进行总线编号。前面介绍过 PCI 桥提供了 Primary Bus Number、Secondary Bus Number 和 Subordinate Bus Number 三个寄存器用于标志该桥所连接的 PCI 总线,下面通过一个示例来说明内核对于 PCI 总线是如何进行编号的。
图 6. 示例

- 系统运行初始,Bus A 为 0,通过上面的 PCI 总线扫描得到连接在 Bus A 上的 PCI 桥(即图中的 Bridge 1)。
- 下面开始设置 Bridge 1 的 Bus 寄存器。将 Primary Bus Number 寄存器设置成 Bus A 的编号,即 0。将 Secondary Bus Number 寄存器设置成 Bus B 的编号,它的值等于(Bus A + 1),也就是 1。由于暂时无法知道该桥所能访问的所有下行总线数目,Subordinate Bus Number 寄存器暂时设置成 0xFF。
- 当扫描完所有 Bus A 上所有(设备号,功能号)后,开始扫描 Bus B,Bus B 的编号在扫描完 Bus A 后已经得到,为 1。Bus B 的扫描方法同步骤(1),先扫描出 Bus B 上的 PCI 桥(即图中的 Bridge 2),然后配置 Primary Bus Number 寄存器为 1,Secondary Bus Number 寄存器为 2,而 Subordinate Bus Number 寄存器依然为 0xFF。
- Bus B 扫描完后得到 Bus C 的编号,为2。下面开始扫描 Bus C,因为 Bus C 上没有 PCI 桥,于是在扫描完其它(设备号,功能号)后,Bus C 的扫描结束。
- 由于 Bridge 2 所能访问到的最大 Bus 编号是 2,因此重新设置 Bridge 2 的 Subordinate Bus Number 寄存器为 2。
- 由于 Bridge 1 所能访问到的最大 Bus 编号也是 2,因此重新设置 Bridge 1 的 Subordinate Bus Number 寄存器为 2。
- 总线编号结束。
配置访问空间
当系统需要访问 PCI 设备时,它需要产生 Configuration、Memory 或者 IO 的读写操作,对于 Memory/IO 的访问方式来说,它们需要定义一个地址范围,落在这个地址范围的操作会被认为是相应的 Memory/IO 的读写操作。
通常 PCI 设备提供了最多6组 Base Address 寄存器,在 PCI 总线扫描时,每当扫描出一个可用的 PCI 设备后,会对该设备的 Base Address 寄存器进行 Memory/IO 访问空间的配置。
而对于 PCI 桥来说,它只提供了2组 Base Address 寄存器,当 PCI 总线扫描出一个 PCI 桥后,也会对该桥的 Base Address 寄存器进行 Memory/IO 访问空间的配置。
需要注意的是,在构建系统之初,需要明确当前系统的地址范围,划分出特定的物理地址作为 PCI Memory 或者 PCI IO 空间,在给 PCI 设备/桥进行访问空间配置时,就是取事先约定的地址空间中的某段地址进行配置,所有设备/桥的访问地址不能冲突。定义系统的 Memory/IO 访问空间是在 mpc85xx_setup_hose() 函数中提供的(位于 arch/ppc/syslib/ppc85xx_setup.c 中)。
PCI 设备和总线初始化
这一操作在 pcibios_init() 函数中进行(位于 arch/ppc/kernel/pci.c 中)。它会在前面操作结束后,对 PCI 总线和 PCI 设备分别分配 pci_bus 和 pci_dev 类型的节点,并建立如所示的组织结构关系。
Linux 的 PCI 设备初始化
Linux 会将 PCI 的相关信息保存在一个文件中,从而方便用户的查阅。这一文件的创建就在 pci_proc_init() 函数中进行(位于 drivers/pci/proc.c 中)。首先它在 /proc/bus 目录下建立起一个名为 pci 的目录,然后在该目录中建立一个名为 devices 的文件,该文件中存放了当前内核所配置的所有 PCI 设备的信息。
我们通常会使用 lspci 命令来查看系统中的 PCI 设备,这条命令就是从 devices 文件中解析相应的字段来显示的。
![]() ![]() |
总结
PCI 标准更新很快,现在最新的标准被称为 PCI Express,从硬件角度来看与以前的 PCI 有了很大的区别。但是由于 PCI 标准的兼容性,其设备配置空间的布局仍然相同,从而也保证了软件的兼容性,对于 PCI Express 的内核配置与 PCI 基本相同。良好的兼容性——这大概也是 PCI 的一个魅力所在吧!(责任编辑:A6)