/* Configuration request Retry Status */ while (l == 0xffff0001) { msleep(delay); delay *= 2;
if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l)) return NULL;
/* Card hasn't responded in 60 seconds? Must be stuck. */ if (delay > 60 * 1000) {
printk(KERN_WARNING \ \ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); return NULL; } }
从配置空间中读取该设备对应的vendor id和device id.如果读出来的值,有一个是空的,则说明该功能号对应的设备不存在,或者是配置非法.
如果读出来的是0xffff0001.则需要重新读一次,如果重读次数过多,也会退出
if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type)) return NULL;
dev = alloc_pci_dev(); if (!dev)
return NULL;
dev->bus = bus;
dev->sysdata = bus->sysdata; dev->dev.parent = bus->bridge; dev->dev.bus = &pci_bus_type; dev->devfn = devfn;
dev->hdr_type = hdr_type & 0x7f; dev->multifunction = !!(hdr_type & 0x80); dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; dev->cfg_size = pci_cfg_space_size(dev); dev->error_state = pci_channel_io_normal; set_pcie_port_type(dev);
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) set this higher, assuming the system even supports it. */ dev->dma_mask = 0xffffffff;
接着,将不同类型设备的共同头部配置读出来,然后赋值给pci_dev的相应成员.这里有个特别要值得注意的地方:
9
dev->dev.bus = &pci_bus_type.即将pci_dev里面封装的device结构的bus设置为了pci_bus_type.这个是很核心的一个步骤.我们先将它放到这里,之后的再来详细分析
特别的, HEADER_TYPE的最高位为0,表示该设备是一个单功能设备
if (pci_setup_device(dev) < 0) { kfree(dev); return NULL; }
return dev; }
最后,流程就会转入到pci_setup_deivce()对特定类型的设备配置都行读取操作了.代码如下: static int pci_setup_device(struct pci_dev * dev) {
u32 class;
sprintf(pci_name(dev), \ 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;
pr_debug(\ dev->vendor, dev->device, class, dev->hdr_type);
/* \
dev->current_state = PCI_UNKNOWN;
/* Early fixups, before probing the BARs */ pci_fixup_device(pci_fixup_early, dev); class = dev->class >> 8;
switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */ if (class == PCI_CLASS_BRIDGE_PCI) goto bad; pci_read_irq(dev);
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);
10
/*
* Do the ugly legacy mode stuff here rather than broken chip * quirk code. Legacy mode ATA controllers have fixed * addresses. These are not always echoed in BAR0-3, and * BAR0-3 in a few cases contain junk! */
if (class == PCI_CLASS_STORAGE_IDE) { u8 progif;
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); if ((progif & 1) == 0) {
dev->resource[0].start = 0x1F0; dev->resource[0].end = 0x1F7;
dev->resource[0].flags = LEGACY_IO_RESOURCE; dev->resource[1].start = 0x3F6; dev->resource[1].end = 0x3F6;
dev->resource[1].flags = LEGACY_IO_RESOURCE; }
if ((progif & 4) == 0) {
dev->resource[2].start = 0x170; dev->resource[2].end = 0x177;
dev->resource[2].flags = LEGACY_IO_RESOURCE; dev->resource[3].start = 0x376; dev->resource[3].end = 0x376;
dev->resource[3].flags = LEGACY_IO_RESOURCE; } } break;
case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ if (class != PCI_CLASS_BRIDGE_PCI) goto bad;
/* The PCI-to-PCI bridge spec requires that subtractive decoding (i.e. transparent) bridge must have programming interface code of 0x01. */ pci_read_irq(dev);
dev->transparent = ((dev->class & 0xff) == 1); pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); break;
case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ if (class != PCI_CLASS_BRIDGE_CARDBUS) goto bad; pci_read_irq(dev); pci_read_bases(dev, 1, 0);
11
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;
default: /* unknown header */
printk(KERN_ERR \ pci_name(dev), dev->hdr_type); return -1;
bad:
printk(KERN_ERR \ pci_name(dev), class, dev->hdr_type); dev->class = PCI_CLASS_NOT_DEFINED; }
/* We found a fine healthy device, go go go... */ return 0; }
总共有三种类型的设备,分别为常规设备(PCI_HEADER_TYPE_NORMAL) ,pci-pci桥设备(PCI_HEADER_TYPE_BRIDGE),笔记本电脑上使用的cardbus(PCI_HEADER_TYPE_CARDBUS).这里的操作不外乎是IRQ的确定,设备存储区间映射等.先将这几个操作分析如下: 1: IRQ号的确定
该操作接口为pci_read_irq():
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; }
在PCI_INTERRUPT_PIN中存放的是将INTA~INTD的哪一个引脚连接到了中断控制器,如果该值为零.说明并末将引脚连接至中断控制器.自然也就不能产生中断信号.
其实,在PCI_INTERRUPT_LINE存放的是该设备的中断线连接在中断控制器的哪一个IRQ线上.也就是对应设备的IRQ.
注意这里的寄存器只读有意义,并不是更改寄存器的值就更改该设备的IRQ
2:内部存储区间的确定
从之前的pci设备配置寄存器图中可以看到.有从0x10~0x27的6个base address寄存器.里面存放的就是内部存储器的地起地址和长度,及其类型.
首先将对应寄存器的值取出.如果最低位为1.则说明该区域是I/O端口,高29位是端口地址的高29位,低3位为零.否则是存储映射区间.前28位是存储区的高28位,低四位为零.
12