在pci_create_root_bus 中 首先会申请一个pci的root bus
struct pci_bus *b;
b = pci_alloc_bus(NULL);
if (!b)
return NULL;
b->sysdata = sysdata;
b->ops = ops;
b->number = b->busn_res.start = bus;
#ifdef CONFIG_PCI_DOMAINS_GENERIC
b->domain_nr = pci_bus_find_domain_nr(b, parent);
#endif
然后会再申请一个host bridge
bridge = pci_alloc_host_bridge(b);
if (!bridge)
goto err_out;
从pci_alloc_host_bridge 中可以看到pcie的root bus是挂在host bridge下面的
static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
{
struct pci_host_bridge *bridge;
bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
if (!bridge)
return NULL;
INIT_LIST_HEAD(&bridge->windows);
bridge->bus = b;
return bridge;
}
在pci_alloc_host_bridge 中先申请一个pci_host_bridge 结构体,然后将bridge->bus 指向b,这个b就是前面申请的pci root bus,因此验证了前面的说明一个rc是有host bridge -> root bus -> root port 组成的.
bridge->dev.parent = parent;
bridge->dev.release = pci_release_host_bridge_dev;
因为这里的pci_create_root_bus 可能是switch 设备的bus,因为要对bridge->dev.parent 赋值parent,如果是root bus的话,parent 就等于NULL。
acpi_pci_root_create->pci_create_root_bus 调用时,明显看到parent是NULL。
再调用
dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
来设定device的name,这样就可以在/sys/devices 下面看到以pci开始的device了,
root@ubuntu:/sys/devices# ls
LNXSYSTM:00 pci0002:80 pci0006:c0 pci000c:20 pnp0 tracepoint
armv8_pmuv3 pci0004:88 pci0007:90 pci000d:30 software virtual
breakpoint pci0005:00 pci000a:10 platform system
这里的domain就是pci 的segment了,具体也是在pci_create_root_bus 中通过
#ifdef CONFIG_PCI_DOMAINS_GENERIC
b->domain_nr = pci_bus_find_domain_nr(b, parent);
#endif
来赋值的.
int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
{
return acpi_disabled ? of_pci_bus_find_domain_nr(parent) :
acpi_pci_bus_find_domain_nr(bus);
}
由于我们使用的acpi因此走acpi_pci_bus_find_domain_nr
int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
{
struct pci_config_window *cfg = bus->sysdata;
struct acpi_device *adev = to_acpi_device(cfg->parent);
struct acpi_pci_root *root = acpi_driver_data(adev);
return root->segment;
}
这就比较清楚的看到在pci中所谓的domain就是pci的segment。
error = pcibios_root_bridge_prepare(bridge);
if (error) {
kfree(bridge);
goto err_out;
}
pcibios_root_bridge_prepare 这个函数在arm64 下只有在非apci mode下才意义,如果是acpi mode相当与空函数
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
if (!acpi_disabled) {
struct pci_config_window *cfg = bridge->bus->sysdata;
struct acpi_device *adev = to_acpi_device(cfg->parent);
ACPI_COMPANION_SET(&bridge->dev, adev);
}
return 0;
}
注册bridge 对应的device,并给bus下面的bridage赋值.
error = device_register(&bridge->dev);
if (error) {
put_device(&bridge->dev);
goto err_out;
}
b->bridge = get_device(&bridge->dev);
给bus下的device 赋值和bus相同的domain
pci_set_bus_msi_domain(b);
给root bus赋值
b->dev.class = &pcibus_class;
b->dev.parent = b->bridge;
dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
error = device_register(&b->dev);
这样就可以在/sys/bus/pci/devices 下面看到pci bus下面挂了多少个devices.
root@ubuntu:/sys/bus/pci/devices# ls
0002:80:00.0 0005:00:00.0 0007:90:00.0 000a:10:00.0 000d:30:00.0
0004:88:00.0 0006:c0:00.0 0007:91:00.0 000c:20:00.0
在开机log中可以通过下面的log找到系统中有多少个host bridge
if (parent)
dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
else
printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
[ 13.411622] PCI host bridge to bus 0002:80
[ 13.411622] PCI host bridge to bus 0002:80
可以看到系统中有两个host bridge ???。
/* Add initial resources to the bus */
resource_list_for_each_entry_safe(window, n, resources) {
list_move_tail(&window->node, &bridge->windows);
res = window->res;
offset = window->offset;
if (res->flags & IORESOURCE_BUS)
pci_bus_insert_busn_res(b, bus, res->end);
else
pci_bus_add_resource(b, res, 0);
if (offset) {
if (resource_type(res) == IORESOURCE_IO)
fmt = " (bus address [%#06llx-%#06llx])";
else
fmt = " (bus address [%#010llx-%#010llx])";
snprintf(bus_addr, sizeof(bus_addr), fmt,
(unsigned long long) (res->start - offset),
(unsigned long long) (res->end - offset));
} else
bus_addr[0] = '\0';
dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr);
}
通过这段code 给bus添加资源,可以通过在开机log 中查找dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr);
[ 13.419865] pci_bus 0002:80: root bus resource [mem 0xa8800000-0xaffeffff window]
[ 13.419865] pci_bus 0002:80: root bus resource [mem 0xa8800000-0xaffeffff window]
[ 13.434941] pci_bus 0002:80: root bus resource [io 0x0000-0xffff window]
[ 13.434941] pci_bus 0002:80: root bus resource [io 0x0000-0xffff window]
[ 13.448617] pci_bus 0002:80: root bus resource [bus 80-87]
[ 13.448617] pci_bus 0002:80: root bus resource [bus 80-87]
来得到root bus的资源,从log看bus的资源分为3类,及mem/io/bus
最后将bus的node添加到pci_root_buses 中
list_add_tail(&b->node, &pci_root_buses);
而pci_root_buses是一个list,其定义为extern struct list_head pci_root_buses; /* list of all known PCI buses */