PCI 设备枚举
head32.c(貌似更早的初始化,再之前的不敢确定了)
void __init i386_start_kernel(void)
{
switch (boot_params.hdr.hardware_subarch) {
case X86_SUBARCH_MRST:
x86_mrst_early_setup();
break;
}
mrst.c(x86_init.pci.init的来历)
struct pci_ops pci_mrst_ops = {
.read = pci_read,
.write = pci_write,
};
int __init pci_mrst_init(void)
{
pci_mmcfg_late_init();
pcibios_enable_irq = mrst_pci_irq_enable;
pci_root_ops = pci_mrst_ops;
return 1;
}
void __init x86_mrst_early_setup(void)
{
x86_init.pci.init = pci_mrst_init;
x86_init.pci.fixup_irqs = x86_init_noop;
legacy_pic = &null_legacy_pic;
}
legacy.c(真正的枚举从这里开始)
int __init pci_subsys_init(void)
{
/*
* The init function returns an non zero value when
* pci_legacy_init should be invoked.
*/
if (x86_init.pci.init())
pci_legacy_init();
pcibios_fixup_peer_bridges();
x86_init.pci.init_irq();
pcibios_init();
return 0;
}
subsys_initcall(pci_subsys_init);
int __init pci_legacy_init(void)
{
if (!raw_pci_ops) {
printk("PCI: System does not support PCI\n");
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;
}
arch/x86/pci/init.c(解释raw_pci_ops的来历)
在pci规范中,定义了两种操作配置空间的方法,即type1 和type2.在新的设计中,type2的配置机制不会被采用,通常会使用type1.因此,在代码中pci_direct_probe()一般会返回1,即使用type1
int __init pci_direct_probe(void)
{
struct resource *region, *region2;
if ((pci_probe & PCI_PROBE_CONF1) == 0)
goto type2;
region = request_region(0xCF8, 8, "PCI conf1");
if (!region)
goto type2;
if (pci_check_type1()) {
raw_pci_ops = &pci_direct_conf1;
port_cf9_safe = true;
return 1;
}
release_resource(region);
}
void __init pci_direct_init(int type)
{
if (type == 1) {
raw_pci_ops = &pci_direct_conf1;
if (raw_pci_ext_ops)
return;
if (!(pci_probe & PCI_HAS_IO_ECS))
return;
printk(KERN_INFO "PCI: Using configuration type 1 "
"for extended access\n");
raw_pci_ext_ops = &pci_direct_conf1;
return;
}
}
static __init int pci_arch_init(void)
{
#ifdef CONFIG_PCI_DIRECT
int type = 0;
type = pci_direct_probe();
#endif
#ifdef CONFIG_PCI_DIRECT
pci_direct_init(type);
#endif
return 0;
}
arch_initcall(pci_arch_init);
arch/x86/pci/common.c(使用pcibios_scan_root枚举总线号为0的设备,其他总线暂时没有枚举,深度优先遍历)
struct pci_bus * __devinit pcibios_scan_root(int busnum)
{
bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
return bus;
}
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)
b->subordinate = pci_scan_child_bus(b);(枚举该总线下的所有设备)
return b;
}
unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
{
unsigned int devfn, pass, max = bus->secondary;
struct pci_dev *dev;
/* Go find them, Rover! */(按功能号扫描设备)
for (devfn = 0; devfn < 0x100; devfn += 8)
pci_scan_slot(bus, devfn);
return max;
}
int pci_scan_slot(struct pci_bus *bus, int devfn)
{
dev = pci_scan_single_device(bus, devfn);
if (!dev)
return 0;
if (!dev->is_added)
nr++;
if (pci_ari_enabled(bus))(根据不同的类型设置不同的回调函数)
next_fn = next_ari_fn;
else if (dev->multifunction)
next_fn = next_trad_fn;
(扫描设备上的所有功能)
for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) {
dev = pci_scan_single_device(bus, devfn + fn);
if (dev) {
if (!dev->is_added)
nr++;
dev->multifunction = 1;
}
}
}
struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
dev = pci_scan_device(bus, devfn);{
(从设备的配置空间读取 vendor id and device id)
(为pci_dev分配空间并初始化)
dev = alloc_pci_dev();
dev->bus = bus;
dev->devfn = devfn;
dev->vendor = 1 &0xffff;
dev->device = (l >> 16) & 0xffff;
(对特定的设备读取配置空间)
pci_setup_device(dev);
(device制作完毕)
}
if (!dev)
return NULL;
pci_device_add(dev, bus);
return dev;
}
int pci_setup_device(struct pci_dev *dev)
{
u32 class;
u8 hdr_type;
struct pci_slot *slot;
if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
dev->sysdata = dev->bus->sysdata;
dev->dev.parent = dev->bus->bridge;
dev->dev.bus = &pci_bus_type;(pci_driver->drv.bus = &pci_bus_type)
dev->hdr_type = hdr_type & 0x7f;
dev->multifunction = !!(hdr_type & 0x80);(HEADER_TYPE的最高位为0,表示该设备是一个单功能设备)
dev->error_state = pci_channel_io_normal;
set_pcie_port_type(dev);
dev->slot = slot;
dev->dma_mask = 0xffffffff;
dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn));
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
dev->revision = class & 0xff;
class >>= 8;
/* upper 3 bytes */
dev->class = class;
class >>= 8;
(可以将这里换成printk,打印所有的pci设备,调试)
dev_dbg(&dev->dev, "found [%04x:%04x] class %06x header type %02x\n",
dev->vendor, dev->device, class, dev->hdr_type);
dev->cfg_size = pci_cfg_space_size(dev);
dev->current_state = PCI_UNKNOWN;
/* Early fixups, before probing the BARs */
(根据具体不同的类型进行赋值,总共有三种类型的设备,分别为常规设备(PCI_HEADER_TYPE_NORMAL) ,pci-pci桥设备(PCI_HEADER_TYPE_BRIDGE),笔记本电脑上使用的cardbus(PCI_HEADER_TYPE_CARDBUS))
switch (dev->hdr_type) {
/* header type */
case PCI_HEADER_TYPE_NORMAL:
/* standard header */(普通模式)
1.pci_read_irq(dev);
2.pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
if (class == PCI_CLASS_STORAGE_IDE) {
}
case PCI_HEADER_TYPE_BRIDGE:
/* bridge header */(pci-pic桥)
1.pci_read_irq(dev);
dev->transparent = ((dev->class & 0xff) == 1);
2.pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
set_pcie_hotplug_bridge(dev);
pos = pci_find_capability(dev, PCI_CAP_ID_SSVID);
if (pos) {
pci_read_config_word(dev, pos + PCI_SSVID_VENDOR_ID, &dev->subsystem_vendor);
pci_read_config_word(dev, pos + PCI_SSVID_DEVICE_ID, &dev->subsystem_device);
}
break;
case PCI_HEADER_TYPE_CARDBUS:
/* CardBus bridge header */(笔记本)
1.pci_read_irq(dev);
2.pci_read_bases(dev, 1, 0);
pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
break;
}
(在PCI_INTERRUPT_PIN中存放的是将INTA~INTD的哪一个引脚连接到了中断控制器,如果该值为零.说明并末将引脚连接至中断控制器.自然也就不能产生中断信号.
其实,在PCI_INTERRUPT_LINE存放的是该设备的中断线连接在中断控制器的哪一个IRQ线上.也就是对应设备的IRQ)
1.static void pci_read_irq(struct pci_dev *dev)
{
unsigned char irq;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
dev->pin = irq;
if (irq)
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
dev->irq = irq;
}
2:内部存储区间的确定