linux启动过程中pci总线初始化主要包括2部分,pci控制器的注册和pci设备的枚举,pci总线和其他总线一个很重要的区别就是pci总线的枚举,在启动过程中遍历pci总线树上所有可能的dev func,记录下所有存在的设备的vendor id 设备名等,这个是做为后面pci设备驱动初始化中注册pci设备驱动需要匹配的重要依据,类似于platform驱动。
先说pci控制器注册,这个与具体开发板相关,以龙芯1A开发板2.6.33内核为例,在arch/mips/loongson/sb2f/pci.c中部分代码如下:
static struct resource loongson_pci_mem_resource = {
.name = "pci memory space",
.start = 0x14000000UL,
.end = 0x17ffffffUL,
.flags = IORESOURCE_MEM,
};
static struct resource loongson_pci_io_resource = {
.name = "pci io space",
.start = 0x00004000UL,
.end = IO_SPACE_LIMIT,
.flags = IORESOURCE_IO,
};
static struct pci_controller loongson_pci_controller = {
.pci_ops = &sb2f_pci_pci_ops,
.io_resource = &loongson_pci_io_resource,
.mem_resource = &loongson_pci_mem_resource,
.mem_offset = 0x00000000UL,
.io_offset = 0x00000000UL,
};
static void __init setup_pcimap(void)
{
/*
* local to PCI mapping for CPU accessing PCI space
* CPU address space [256M,448M] is window for accessing pci space
* we set pcimap_lo[0,1,2] to map it to pci space[0M,64M], [320M,448M]
*
* pcimap: PCI_MAP2 PCI_Mem_Lo2 PCI_Mem_Lo1 PCI_Mem_Lo0
* [<2G] [384M,448M] [320M,384M] [0M,64M]
*/
SB2F_PCIMAP = 0x46140;
}
static int __init pcibios_init(void)
{
setup_pcimap();
//loongson_pci_controller.io_map_base = mips_io_port_base;
if(!disablepci)
{
register_pci_conroller(&loongson_pci_controller);
}
return 0;
}
在pcibios_init函数中setup_pcimap中设置pci总线的3个mem space空间的高6位, register_pci_conroller函数是对pci控制器提供的mem和io资源做一下检查 然后将pci控制器添加到内核的pci控制器链表中。
这就完成了对特定pci控制器的初始化。特别要注意控制器结构体中的pci_ops成员,这个成员提供的读写函数就是对pci设备配置寄存器的读写。
接下来来看pci总线的枚举,这是非常重要的一部分。
在arch/mips/pci/pci.c中
{
struct pci_controller *hose;
/* Scan all of the recorded PCI controllers. */
for (hose = hose_head; hose; hose = hose->next)
{
pcibios_scanbus(hose);
}
pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq);
pci_initialized = 1;
return 0;
}
在这个pcibios_init函数中,遍历内核pci控制器链表每一个成员,这里我们只有一个控制器,只有一个成员。然后调用pcibus_scanbus来遍历总线,扫描设备。
-------》》》》pcibus_scanbus 参数:hose pci控制器结构体
static void __devinit pcibios_scanbus(struct pci_controller *hose)
{
static int next_busno;
static int need_domain_info;
struct pci_bus *bus;
if (!hose->iommu)
PCI_DMA_BUS_IS_PHYS = 1;
if (hose->get_busno && pci_probe_only)
next_busno = (*hose->get_busno)();
bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
hose->bus = bus;
need_domain_info = need_domain_info || hose->index;
hose->need_domain_info = need_domain_info;
if (bus) {
next_busno = bus->subordinate + 1;
/* Don't allow 8-bit bus number overflow inside the hose -
reserve some space for bridges. */
if (next_busno > 224) {
next_busno = 0;
need_domain_info = 1;
}
if (!pci_probe_only) {
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
pci_enable_bridges(bus);
}
}
}
从前面pci控制器的注册可以知道get_busno为NULL,并且pci_probe_only为0,因此next_busno为0。调用pci_scan_bus
--------》》》》pci_scan_bus 参数:next_busno=0 hose->pci_ops hose
static inline struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
void *sysdata)
{
struct pci_bus *root_bus;
root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
if (root_bus)
pci_bus_add_devices(root_bus);
return root_bus;
}
这个函数实现对pci根总线的初始化
------》》》》pci_scan_bus_parented 参数:NULL 0 hose->ops hose
struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
int bus, struct pci_ops *ops, void *sysdata)
{
struct pci_bus *b;
b = pci_create_bus(parent, bus, ops, sysdata);
if (b)