if (pcibios_assign_all_busses())
/* Temporarily disable forwarding of the configuration cycles on all bridges in this bus segment to avoid possible conflicts in the second pass between two bridges programmed with overlapping bus ranges. */
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses & ~0xffffff); goto out; }
/* Clear errors */ //往状态寄存器全写1
pci_write_config_word(dev, PCI_STATUS, 0xffff);
/* Prevent assigning a bus number that already exists. * This can happen when a bridge is hot-plugged */ //要处理的总线编号是否已经存在了 if (pci_find_bus(pci_domain_nr(bus), max+1)) goto out;
child = pci_add_new_bus(bus, dev, ++max); buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) | ((unsigned int)(child->subordinate) << 16);
/*
* yenta.c forces a secondary latency timer of 176. * Copy that behaviour here. */
if (is_cardbus) {
buses &= ~0xff000000;
buses |= CARDBUS_LATENCY_TIMER << 24; }
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
if (!is_cardbus) {
child->bridge_ctl = bctl;
pci_fixup_parent_subordinate_busnr(child, max); /* Now we can scan all subordinate buses... */
17
max = pci_scan_child_bus(child);
pci_fixup_parent_subordinate_busnr(child, max); } else {
for (i=0; i while (parent->parent) { if ((!pcibios_assign_all_busses()) && (parent->subordinate > max) && (parent->subordinate <= max+i)) { j = 1; } parent = parent->parent; } if (j) { i /= 2; break; } } max += i; pci_fixup_parent_subordinate_busnr(child, max); } child->subordinate = max; pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); } sprintf(child->name, (is_cardbus ? \ /* Has only triggered on CardBus, fixup is in yenta_socket */ while (bus->parent) { if ((child->subordinate > bus->subordinate) || (child->number > bus->subordinate) || (child->number < bus->number) || (child->subordinate < bus->number)) { pr_debug(\ \ child->number, child->subordinate, (bus->number > child->subordinate && bus->subordinate < child->number) ? \ bus->self->transparent ? \ bus->number, bus->subordinate); 18 } bus = bus->parent; } out: pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl); return max; } 忽略有关cardbus总线相关的部份。PCI_PRIMARY_BUS寄存器中的值的含义为:从低位到高位分别为:主总线号,次总线号,子层最大线号。各占两位。如果从PCI_PRIMARY_BUS取出来的值,次总线号和子层最大线号有意义。说明该pci-bridge是被bios处理过的。 这里为什么没有判断主总线号的值呢?这是因为总主线号可能为零,如根总线。而次总线是每枚举到一个pci-bridge就会增1。 如果该pci bridge是被bios处理过的,那直接构造一个pci_bus(pci_add_new_bus()).再递归枚举这个pci_bus下的设备就可以了。 相反,如果该pci-bridge没有被bios处理过,那就需要我们手动去处理了。这时,为它分配一个可能的总线号。然后将总线号写入PCI_PRIMARY_BUS寄存器。再构造一个pci_bus.递归枚举其下的设备。 最后的一个while()循环是打印出一些DEBUG信息。不需要理会 TODO:在上述代码红色标识部份。如果是没有由bios处理过的pci-bridge.有效设置只是次总线号和下层最大总线号。难道不需要设置主总线号么? 特别注意.在遍其次级总线下层pci时.此时还不知道下层最大总号是多少.所以将pci_bus->subordinate赋值为了0xFF.即其下的所有设备都可以透过这个pci-bridge(参考pci_alloc_child_bus()中的处理).然后等下层的子总线遍历完了之后,再来确定子总线的最大总线号,将其更新至pci_bus->subordinate. 对于上次主总线号的疑问:其实这个总主线号在访问下层总线是不会被使用到的,因为在配置的时候,只会比较pci_bridge的次总线号和下层最大总线号.如果总线号落在这个区间中间.将其透传到下一层总线.否则,忽略这个请求. 递归完成之后,pci总线上的所有信息都被找到了。所有pci_bus被存放在pci_root_buses为根的倒立树中.而总线上对应的pci 设备存放在pci_bus->device链表中. 返回到我们开篇时的初始化函数pci_legacy_init().这个函数还剩下一部份.代码如下: static int __init pci_legacy_init(void) { if (!raw_pci_ops) { printk(\ return 0; } if (pcibios_scanned++) return 0; printk(\ pci_root_bus = pcibios_scan_root(0); if (pci_root_bus) pci_bus_add_devices(pci_root_bus); 19 pcibios_fixup_peer_bridges(); return 0; } 如果总线遍历成功,就会转入pci_bus_add_devices().代码片段如下: void pci_bus_add_devices(struct pci_bus *bus) { …… …… pci_bus_add_device(dev) …… …… } 该函数会遍历总线上的device链表.然后对每个设备调用pci_bus_add_device().代码如下: int pci_bus_add_device(struct pci_dev *dev) { int retval; retval = device_add(&dev->dev); if (retval) return retval; down_write(&pci_bus_sem); list_add_tail(&dev->global_list, &pci_devices); up_write(&pci_bus_sem); pci_proc_attach_device(dev); pci_create_sysfs_dev_files(dev); return 0; } 从上面的代码可以看出.它先将设备添加,然后再将设备挂载到全局的pci_devices链表上. 这样顺着pci_devices就可以找到所有的设备信息了. 另外,对于pci_dev的初始化,我们之前曾强调过.初始化代码片段如下: static struct pci_dev * __devinit pci_scan_device(struct pci_bus *bus, int devfn) { …… …… dev->dev.parent = bus->bridge; dev->dev.bus = &pci_bus_type; …… …… } 即该设备是属于pci_bus_type总线的.事实上,我们编写的pci驱动程序,也是基于pci_bus_type.这样,就可以在添加 20 驱动的时候,就可以匹配想要的设备了. 在这里,特别注意一下,经过这里的枚举,只是枚举完了第一条根总线.那其它的根总线是在什么地方被枚举的呢? 在下一节里,再来分析这个问题. 六:小结 在linux的pci架构中,大量运用了深度优先遍历算法.这是由pci总线结构所决定的.经过这一章的分析过后,我们应该对pci架构有了一定的了解.同时在这一章还留下了一个问题.到下一节再来进行分析. 21