pci 初始化

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 拓扑结构的建立.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值