pcie的初始化从acpi_init 开始。
static int __init acpi_init(void)
{
acpi_scan_init();
}
subsys_initcall(acpi_init);
可见是kernel自动调用acpi_init来执行,
acpi_init->acpi_scan_init->acpi_bus_scan->acpi_bus_check_add->acpi_scan_init_hotplug->acpi_scan_match_handler->acpi_scan_handler_matching
static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
const char *idstr,
const struct acpi_device_id **matchid)
{
const struct acpi_device_id *devid;
if (handler->match)
return handler->match(idstr, matchid);
for (devid = handler->ids; devid->id[0]; devid++)
if (!strcmp((char *)devid->id, idstr)) {
if (matchid)
*matchid = devid;
return true;
}
return false;
}
这个函数会比较biso是否传递PNP0A03 字符串,而这个字符串代表的是pcie的root。
static const struct acpi_device_id root_device_ids[] = {
{"PNP0A03", 0},
{"", 0},
};
static struct acpi_scan_handler pci_root_handler = {
.ids = root_device_ids,
.attach = acpi_pci_root_add,
.detach = acpi_pci_root_remove,
.hotplug = {
.enabled = true,
.scan_dependent = acpi_pci_root_scan_dependent,
},
};
如果找到PNP0A03,则在
int acpi_bus_scan(acpi_handle handle)
{
void *device = NULL;
if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_check_add, NULL, NULL, &device);
if (device) {
acpi_bus_attach(device);
return 0;
}
return -ENODEV;
}
acpi_bus_scan 中调用acpi_bus_attach->acpi_scan_attach_handler
static int acpi_scan_attach_handler(struct acpi_device *device)
{
struct acpi_hardware_id *hwid;
int ret = 0;
list_for_each_entry(hwid, &device->pnp.ids, list) {
const struct acpi_device_id *devid;
struct acpi_scan_handler *handler;
handler = acpi_scan_match_handler(hwid->id, &devid);
if (handler) {
if (!handler->attach) {
device->pnp.type.platform_id = 0;
continue;
}
device->handler = handler;
ret = handler->attach(device, devid);
if (ret > 0)
break;
device->handler = NULL;
if (ret < 0)
break;
}
}
return ret;
}
这个函数最终调用handler->attach,对于pcie root则是acpi_pci_root_add
这个函数中就会scan root bridge.
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
int domain = root->segment;
int busnum = root->secondary.start;
int node = pci_acpi_root_get_node(root);
struct pci_bus *bus;
if (pci_ignore_seg)
root->segment = domain = 0;
if (domain && !pci_domains_supported) {
printk(KERN_WARNING "pci_bus %04x:%02x: "
"ignored (multiple domains not supported)\n",
domain, busnum);
return NULL;
}
bus = pci_find_bus(domain, busnum);
if (bus) {
/*
* If the desired bus has been scanned already, replace
* its bus->sysdata.
*/
struct pci_sysdata sd = {
.domain = domain,
.node = node,
.companion = root->device
};
memcpy(bus->sysdata, &sd, sizeof(sd));
} else {
struct pci_root_info *info;
info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
if (!info)
dev_err(&root->device->dev,
"pci_bus %04x:%02x: ignored (out of memory)\n",
domain, busnum);
else {
info->sd.domain = domain;
info->sd.node = node;
info->sd.companion = root->device;
bus = acpi_pci_root_create(root, &acpi_pci_root_ops,
&info->common, &info->sd);
}
}
/* After the PCI-E bus has been walked and all devices discovered,
* configure any settings of the fabric that might be necessary.
*/
if (bus) {
struct pci_bus *child;
list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child);
}
return bus;
}
pci_acpi_scan_root 首先调用pci_find_bus来找root bridge.正常情况下应该找不到root bridge 从而调用
acpi_pci_root_create 来create root bridge.
struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
struct acpi_pci_root_ops *ops,
struct acpi_pci_root_info *info,
void *sysdata)
{
bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
sysdata, &info->resources);
pci_scan_child_bus(bus);
pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge),
}
acpi_pci_root_create 首先调用pci_create_root_bus 来create bus,然后调用pci_scan_child_bus 来scan
unsigned int pci_scan_child_bus(struct pci_bus *bus)
{
for (devfn = 0; devfn < 0x100; devfn += 8)
pci_scan_slot(bus, devfn);
for (pass = 0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list) {
if (pci_is_bridge(dev))
max = pci_scan_bridge(bus, dev, max, pass);
}
return max;
}
pci_scan_child_bus 首先调用pci_scan_slot 来scan 单个pci设备,然后调用pci_scan_bridge 来scan子总线的设备。在pci_scan_bridge 中又会递归
调用pci_scan_child_bus。从而完成整个pci 拓扑结构的建立.
static int __init acpi_init(void)
{
acpi_scan_init();
}
subsys_initcall(acpi_init);
可见是kernel自动调用acpi_init来执行,
acpi_init->acpi_scan_init->acpi_bus_scan->acpi_bus_check_add->acpi_scan_init_hotplug->acpi_scan_match_handler->acpi_scan_handler_matching
static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
const char *idstr,
const struct acpi_device_id **matchid)
{
const struct acpi_device_id *devid;
if (handler->match)
return handler->match(idstr, matchid);
for (devid = handler->ids; devid->id[0]; devid++)
if (!strcmp((char *)devid->id, idstr)) {
if (matchid)
*matchid = devid;
return true;
}
return false;
}
这个函数会比较biso是否传递PNP0A03 字符串,而这个字符串代表的是pcie的root。
static const struct acpi_device_id root_device_ids[] = {
{"PNP0A03", 0},
{"", 0},
};
static struct acpi_scan_handler pci_root_handler = {
.ids = root_device_ids,
.attach = acpi_pci_root_add,
.detach = acpi_pci_root_remove,
.hotplug = {
.enabled = true,
.scan_dependent = acpi_pci_root_scan_dependent,
},
};
如果找到PNP0A03,则在
int acpi_bus_scan(acpi_handle handle)
{
void *device = NULL;
if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_check_add, NULL, NULL, &device);
if (device) {
acpi_bus_attach(device);
return 0;
}
return -ENODEV;
}
acpi_bus_scan 中调用acpi_bus_attach->acpi_scan_attach_handler
static int acpi_scan_attach_handler(struct acpi_device *device)
{
struct acpi_hardware_id *hwid;
int ret = 0;
list_for_each_entry(hwid, &device->pnp.ids, list) {
const struct acpi_device_id *devid;
struct acpi_scan_handler *handler;
handler = acpi_scan_match_handler(hwid->id, &devid);
if (handler) {
if (!handler->attach) {
device->pnp.type.platform_id = 0;
continue;
}
device->handler = handler;
ret = handler->attach(device, devid);
if (ret > 0)
break;
device->handler = NULL;
if (ret < 0)
break;
}
}
return ret;
}
这个函数最终调用handler->attach,对于pcie root则是acpi_pci_root_add
这个函数中就会scan root bridge.
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
int domain = root->segment;
int busnum = root->secondary.start;
int node = pci_acpi_root_get_node(root);
struct pci_bus *bus;
if (pci_ignore_seg)
root->segment = domain = 0;
if (domain && !pci_domains_supported) {
printk(KERN_WARNING "pci_bus %04x:%02x: "
"ignored (multiple domains not supported)\n",
domain, busnum);
return NULL;
}
bus = pci_find_bus(domain, busnum);
if (bus) {
/*
* If the desired bus has been scanned already, replace
* its bus->sysdata.
*/
struct pci_sysdata sd = {
.domain = domain,
.node = node,
.companion = root->device
};
memcpy(bus->sysdata, &sd, sizeof(sd));
} else {
struct pci_root_info *info;
info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
if (!info)
dev_err(&root->device->dev,
"pci_bus %04x:%02x: ignored (out of memory)\n",
domain, busnum);
else {
info->sd.domain = domain;
info->sd.node = node;
info->sd.companion = root->device;
bus = acpi_pci_root_create(root, &acpi_pci_root_ops,
&info->common, &info->sd);
}
}
/* After the PCI-E bus has been walked and all devices discovered,
* configure any settings of the fabric that might be necessary.
*/
if (bus) {
struct pci_bus *child;
list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child);
}
return bus;
}
pci_acpi_scan_root 首先调用pci_find_bus来找root bridge.正常情况下应该找不到root bridge 从而调用
acpi_pci_root_create 来create root bridge.
struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
struct acpi_pci_root_ops *ops,
struct acpi_pci_root_info *info,
void *sysdata)
{
bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
sysdata, &info->resources);
pci_scan_child_bus(bus);
pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge),
}
acpi_pci_root_create 首先调用pci_create_root_bus 来create bus,然后调用pci_scan_child_bus 来scan
unsigned int pci_scan_child_bus(struct pci_bus *bus)
{
for (devfn = 0; devfn < 0x100; devfn += 8)
pci_scan_slot(bus, devfn);
for (pass = 0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list) {
if (pci_is_bridge(dev))
max = pci_scan_bridge(bus, dev, max, pass);
}
return max;
}
pci_scan_child_bus 首先调用pci_scan_slot 来scan 单个pci设备,然后调用pci_scan_bridge 来scan子总线的设备。在pci_scan_bridge 中又会递归
调用pci_scan_child_bus。从而完成整个pci 拓扑结构的建立.