上篇文章已经分析了探测PCI总线的部分代码,碍于篇幅,这里另启一篇。重点分析下pci_scan_root_bus函数
2016-10-24
pci_scan_root_bus函数
struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources) { struct pci_host_bridge_window *window; bool found = false; struct pci_bus *b; int max; /*寻找bus的资源*/ list_for_each_entry(window, resources, list) if (window->res->flags & IORESOURCE_BUS) { found = true; break; } /*创建bus对应的结构*/ b = pci_create_root_bus(parent, bus, ops, sysdata, resources); if (!b) return NULL; if (!found) { dev_info(&b->dev, "No busn resource found for root bus, will use [bus %02x-ff] ", bus); pci_bus_insert_busn_res(b, bus, 255); } /*遍历子总线*/ max = pci_scan_child_bus(b); if (!found) pci_bus_update_busn_res_end(b, max); pci_bus_add_devices(b); return b; }
这里首先寻找bus总线号资源,前面在x86_pci_root_bus_resources函数中已经分配了,所以这里理论上是已经分配好了,不过还是验证下!!内核中总是精益求精。接着调用了pci_create_root_bus函数创建了对应的bus结构,然后调用pci_scan_child_bus函数遍历该总线下所有的子总线。最后就调用pci_bus_add_devices添加设备。总体上就是这么几步,但是要弄清楚,还真是不小的工作量。我们一步步来:
1、pci_create_root_bus函数
1 struct pci_bus *pci_create_root_bus(struct device *parent, int bus, 2 struct pci_ops *ops, void *sysdata, struct list_head *resources) 3 { 4 int error; 5 struct pci_host_bridge *bridge; 6 struct pci_bus *b, *b2; 7 struct pci_host_bridge_window *window, *n; 8 struct resource *res; 9 resource_size_t offset; 10 char bus_addr[64]; 11 char *fmt; 12 /*创建一个pci_bus结构*/ 13 b = pci_alloc_bus(); 14 if (!b) 15 return NULL; 16 /*基本的初始化*/ 17 b->sysdata = sysdata; 18 b->ops = ops; 19 /*0号总线的总线号正是该条根总线下的总线号资源的起始号*/ 20 b->number = b->busn_res.start = bus; 21 /**/ 22 b2 = pci_find_bus(pci_domain_nr(b), bus); 23 if (b2) { 24 /* If we already got to this bus through a different bridge, ignore it */ 25 dev_dbg(&b2->dev, "bus already known "); 26 goto err_out; 27 } 28 29 bridge = pci_alloc_host_bridge(b); 30 if (!bridge) 31 goto err_out; 32 33 bridge->dev.parent = parent; 34 bridge->dev.release = pci_release_host_bridge_dev; 35 dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); 36 error = pcibios_root_bridge_prepare(bridge); 37 if (error) { 38 kfree(bridge); 39 goto err_out; 40 } 41 /*桥也是作为一个设备存在*/ 42 error = device_register(&bridge->dev); 43 if (error) { 44 put_device(&bridge->dev); 45 goto err_out; 46 } 47 /*建立总线到桥的指向*/ 48 b->bridge = get_device(&bridge->dev); 49 device_enable_async_suspend(b->bridge); 50 pci_set_bus_of_node(b); 51 52 if (!parent) 53 set_dev_node(b->bridge, pcibus_to_node(b)); 54 55 b->dev.class = &pcibus_class; 56 b->dev.parent = b->bridge; 57 dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus); 58 error = device_register(&b->dev); 59 if (error) 60 goto class_dev_reg_err; 61 62 pcibios_add_bus(b); 63 64 /* Create legacy_io and legacy_mem files for this bus */ 65 pci_create_legacy_files(b); 66 67 if (parent) 68 dev_info(parent, "PCI host bridge to bus %s ", dev_name(&b->dev)); 69 else 70 printk(KERN_INFO "PCI host bridge to bus %s ", dev_name(&b->dev)); 71 72 /* Add initial resources to the bus */ 73 list_for_each_entry_safe(window, n, resources, list) { 74 /*从全局的资源链表摘下,加入到特定桥的windows链表中*/ 75 list_move_tail(&window->list, &bridge->windows); 76 77 res = window->res; 78 offset = window->offset; 79 /*如果资源是总线号资源*/ 80 if (res->flags & IORESOURCE_BUS) 81 pci_bus_insert_busn_res(b, bus, res->end); 82 else 83 pci_bus_add_resource(b, res, 0); 84 /*看总线地址到物理地址的偏移*/ 85 if (offset) { 86 if (resource_type(res) == IORESOURCE_IO) 87 fmt = " (bus address [%#06llx-%#06llx])"; 88 else 89 fmt = " (bus address [%#010llx-%#010llx])"; 90 snprintf(bus_addr, sizeof(bus_addr), fmt, 91 (unsigned long long) (res->start - offset), 92 (unsigned long long) (res->end - offset)); 93 } else 94 bus_addr[0] = '