kernel 中对pci设别的枚举flow如下:
acpi_pci_root_add->pci_acpi_scan_root->acpi_pci_root_create->pci_scan_child_bus->pci_scan_slot
这里的slot表示一个独立的PCI设备,PCI一般是由segment:bus:device:fn 这四部分组成
root@ubuntu:/sdf5# lspci
0002:80:00.0 PCI bridge: Device 19e5:1610 (rev 01)
例如这个里的segmemg是0002.bus是80,device 是00,fn是0
以一张PCI网卡为例上面有四个网卡,这四个网口只是fn不同,但是device是相等的,因此代表这张网卡代表一个slot.
for (devfn = 0; devfn < 0x100; devfn += 8)
pci_scan_slot(bus, devfn);
从这段code中也可以看出device是8 bit的,一个bus上最多只能有256 个device。
pci_scan_slot->pci_scan_single_device->pci_scan_device
static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
u32 l;
if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000))
return NULL;
dev = pci_alloc_dev(bus);
if (!dev)
return NULL;
dev->devfn = devfn;
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
pci_set_of_node(dev);
if (pci_setup_device(dev)) {
pci_bus_put(dev->bus);
kfree(dev);
return NULL;
}
return dev;
}
在pci_scan_device 中是通过pci_bus_read_dev_vendor_id 来读取设备钱32 bit的数据也就是vendor_id 来判断设备是否存在,这个可以从pci endpoint的type 0 和type 1的header中看到。
bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
int crs_timeout)
{
int delay = 1;
if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
return false;
/* some broken boards return 0 or ~0 if a slot is empty: */
if (*l == 0xffffffff || *l == 0x00000000 ||
*l == 0x0000ffff || *l == 0xffff0000)
return false;
/*
* Configuration Request Retry Status. Some root ports return the
* actual device ID instead of the synthetic ID (0xFFFF) required
* by the PCIe spec. Ignore the device ID and only check for
* (vendor id == 1).
*/
while ((*l & 0xffff) == 0x0001) {
if (!crs_timeout)
return false;
msleep(delay);
delay *= 2;
if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
return false;
/* Card hasn't responded in 60 seconds? Must be stuck. */
if (delay > crs_timeout) {
printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not responding\n",
pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
PCI_FUNC(devfn));
return false;
}
}
return true;
}
pci_bus_read_dev_vendor_id 调用pci_bus_read_config_dword 来读32bit的数据,如果读到的数据不是下面这四种中的一种就算发现设备了
(*l == 0xffffffff || *l == 0x00000000 || *l == 0x0000ffff || *l == 0xffff0000)
while ((*l & 0xffff) == 0x0001) {
if (!crs_timeout)
return false;
msleep(delay);
delay *= 2;
if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
return false;
/* Card hasn't responded in 60 seconds? Must be stuck. */
if (delay > crs_timeout) {
printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not responding\n",
pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
PCI_FUNC(devfn));
return false;
}
}
上面这段while循环是针对特殊的PCI设备,一般走不到,因此只要读的vendor id不是上面说到的四种,就算发现设备,就返回true了。
而pci_bus_read_config_dword 是一个宏,具体实现在pci/access.c 中
#define PCI_USER_READ_CONFIG(size, type) \
int pci_user_read_config_##size \
(struct pci_dev *dev, int pos, type *val) \
{ \
int ret = PCIBIOS_SUCCESSFUL; \
u32 data = -1; \
if (PCI_##size##_BAD) \
return -EINVAL; \
raw_spin_lock_irq(&pci_lock); \
if (unlikely(dev->block_cfg_access)) \
pci_wait_cfg(dev); \
ret = dev->bus->ops->read(dev->bus, dev->devfn, \
pos, sizeof(type), &data); \
raw_spin_unlock_irq(&pci_lock); \
*val = (type)data; \
return pcibios_err_to_errno(ret); \
} \
EXPORT_SYMBOL_GPL(pci_user_read_config_##size);
可见最后还是调用bus->ops->read 来读取的。而这个ops的赋值在pcie的配置空间 已经讲过了