日期:2014-05-16  浏览次数:20813 次

mips处理器linux内核pci初始化和设备枚举详解

  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中

static int __init pcibios_init(void)
{
    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来遍历总线,扫描设备。