参考资料:
1) 《Linux内核源代码情景分析》
2) Linux内核源代码(2.6.32)。
本文只讨论比较简单的软硬件配置场景。
系统中的第一条PCI总线(即主PCI总线),挂在“宿主—PCI桥”上。
CPU通过“宿主——PCI桥”就可以访问主PCI总线了。
PC机中通常只有一个“宿主—PCI桥”。但是,通过引入其他类型的PCI桥,可以将更多的总线(可以是PCI总线,也可以是ISA总线)连接到主PCI总线上来。这样一来,系统中就可以有多条总线存在了。
下层PCI总线也可以进一步通过PCI桥,将更下一层的PCI总线连接进来。
在上层总线看来,PCI桥也是连接到本总线上的一个设备。
主PCI总线的编号是0,其他的pci总线编号则从1开始依次递增。PCI总线上的一个设备,可以包含1~8个功能,编号是0~7。每个功能称为一个逻辑设备。
有些设备可能只包含一个逻辑设备。例如,一块网卡,上面可能就一个逻辑设备。
在Linux内核角度来看,这些逻辑设备才是最终的设备。
这样的话,每条PCI总线,最大支持32*8个逻辑设备,即256个逻辑设备。
int __init pci_subsys_init(void)
{
#ifdef CONFIG_X86_NUMAQ
pci_numaq_init();
#endif
#ifdef CONFIG_ACPI
pci_acpi_init();
#endif
#ifdef CONFIG_X86_VISWS
pci_visws_init();
#endif
pci_legacy_init();
pcibios_fixup_peer_bridges();
pcibios_irq_init();
pcibios_init();
return 0;
}
subsys_initcall(pci_subsys_init);static int __init pci_legacy_init(void)
{
if (!raw_pci_ops) {
printk("PCI: System does not support PCI\n");
return 0;
}
if (pcibios_scanned++)
return 0;
printk("PCI: Probing PCI hardware\n");
pci_root_bus = pcibios_scan_root(0);
if (pci_root_bus)
pci_bus_add_devices(pci_root_bus);
return 0;
}因此,最终进入 pci_scan_bus_parented,进而进入pci_scan_child_bus去扫描总线上的设备(这里只关注核心部分,因此跳得有点快^_^)。
struct pci_bus * __devinit pcibios_scan_root(int busnum)
{
struct pci_bus *bus = NULL;
struct pci_sysdata *sd;
while ((bus = pci_find_next_bus(bus)) != NULL) {
if (bus->number == busnum) {
/* Already scanned */
return bus;
}
}
/* Allocate per-root-bus (not per bus) arch-specific data.
* TODO: leak; this memory is never freed.
* It's arguable whether it's worth the trouble to care.
*/
sd = kzalloc(sizeof(*sd), GFP_KERNEL);
if (!sd) {
printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
return NULL;
}
sd->node = get_mp_bus_to_node(busnum);
printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
if (!bus)
kfree(sd);
return bus;
}pci_scan_child_bus的核心代码如下:
for (devfn = 0; devfn < 0x100; devfn += 8) pci_scan_slot(bus, devfn);
这里的devfn,是devicefunction的缩写,即“设备功能”的意思。
相当于是设备号与功能号的组合,高位是设备号,低3-bit是功能号。
int pci_scan_slot(struct pci_bus *bus, int devfn)
{
int fn, nr = 0;
struct pci_dev *dev;
dev = pci_scan_single_device(bus, devfn);
if (dev && !dev->is_added)/* new device? */
nr++;
if (dev && dev->multifunction) {
for (fn = 1; fn < 8; fn++) {
dev = pci_scan_single_device(bus, devfn + fn);
if (dev) {
if (!dev->is_added)
nr++;
dev->multifunction = 1;
}
}
}
/* only one slot has pcie device */
if (bus->self && nr)
pcie_aspm_init_link_state(bus->self);
return nr;
}
原文:http://blog.csdn.net/crazycoder8848/article/details/46536861