}
先在pci_root_buses中判断是否存在这个根总线对应的总线号.如果存在,说明这条总线已经遍历过了,直接退出. Pci_root_ops这是定义的pci设备配置空间的操作.在没有选择CONFIG_PCI_MMCONFIG的情况下,它的操作都会转入我们在上面的分析的,ram_pci_ops中.这个过程非常简单,可以自行分析. 然后,流程转入pci_scan_bus_parented().代码如下:
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; }
在pci_create_bus()中,为对应总线号构建pci_bus,然后将其挂入到pci_root_buses链表.该函数代码比较简单,请自行分析.然后,调用然后pci_scan_child_bus枚举该总线下的所有设备.pci_bus->subordinate表示下流总线的最大总线号.pci_sacn_child_bus()代码如下:
unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) {
unsigned int devfn, pass, max = bus->secondary; struct pci_dev *dev;
pr_debug(\>number);
/* Go find them, Rover! */
//按功能号扫描设备号对应的pci 设备 for (devfn = 0; devfn < 0x100; devfn += 8) pci_scan_slot(bus, devfn); /*
* After performing arch-dependent fixup of the bus, look behind * all PCI-to-PCI bridges on this bus. */
pr_debug(%umber); pcibios_fixup_bus(bus); for (pass=0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list) {
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
6
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) max = pci_scan_bridge(bus, dev, max, pass); } /*
* We've scanned the bus and so we know all about what's on * the other side of any bridges that may be on this bus plus * any devices. *
* Return how far we've got finding sub-buses. */
pr_debug(\ pci_domain_nr(bus), bus->number, max); return max; }
这节的难点就是在这个地方了,从我们之前分析的pci设备配置空间的读写方式可得知.对特定总线.下面最多个32个设备号.每个设备号又对应8 个功能号.我们可以将设备号和功能号放到一起,即占8~15位.在这面的代码中.对每个设备号调用pci_scan_slot()去扫描它下面的8个功能号对应的设备.总而言之,把该总线下面的所有设备都要枚举完.
pci_scan_slot()代码如下:
nt pci_scan_slot(struct pci_bus *bus, int devfn) {
int func, nr = 0; int scan_all_fns;
scan_all_fns = pcibios_scan_all_fns(bus, devfn);
for (func = 0; func < 8; func++, devfn++) { struct pci_dev *dev;
dev = pci_scan_single_device(bus, devfn); if (dev) { nr++;
/*
* If this is a single function device, * don't scan past the first function. */
if (!dev->multifunction) { if (func > 0) {
dev->multifunction = 1; } else { break;
7
} } } else {
if (func == 0 && !scan_all_fns) break; } } return nr; }
对其它的每个设备都会调用pci_scan_single_device().如果是单功能设备(dev->multifunction == 0).则只要判断它的第一个功能号可以了,不需要判断之后功能号对应的设备. Pci_scan_single_device()代码如下:
struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) {
struct pci_dev *dev;
dev = pci_scan_device(bus, devfn); if (!dev)
return NULL;
//将pci_dev加至pci_bus->devices pci_device_add(dev, bus);
return dev; }
对每个设备,都会调用pci_scan_device()执行扫描的过程,如果该设备存在,就会将该设备加入到所属总线的devices链表上.这是在pci_device_add()函数中完成的,这个函数比较简单.这里不做详细分析.我们把注意力集中到pci_scan_device(),这函数有点长,分段分析如下:
static struct pci_dev * __devinit
pci_scan_device(struct pci_bus *bus, int devfn) {
struct pci_dev *dev; u32 l; u8 hdr_type; int delay = 1;
if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l)) return NULL;
/* some broken boards return 0 or ~0 if a slot is empty: */ if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) return NULL;
8
/* 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
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库Linux设备驱动之pci设备的枚举(2)在线全文阅读。
相关推荐: