diff options
Diffstat (limited to 'arch/x86/pci/bus_numa.c')
-rw-r--r-- | arch/x86/pci/bus_numa.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c new file mode 100644 index 000000000..2752c02e3 --- /dev/null +++ b/arch/x86/pci/bus_numa.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/range.h> + +#include "bus_numa.h" + +LIST_HEAD(pci_root_infos); + +static struct pci_root_info *x86_find_pci_root_info(int bus) +{ + struct pci_root_info *info; + + list_for_each_entry(info, &pci_root_infos, list) + if (info->busn.start == bus) + return info; + + return NULL; +} + +int x86_pci_root_bus_node(int bus) +{ + struct pci_root_info *info = x86_find_pci_root_info(bus); + + if (!info) + return NUMA_NO_NODE; + + return info->node; +} + +void x86_pci_root_bus_resources(int bus, struct list_head *resources) +{ + struct pci_root_info *info = x86_find_pci_root_info(bus); + struct pci_root_res *root_res; + struct resource_entry *window; + bool found = false; + + if (!info) + goto default_resources; + + printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n", + bus); + + /* already added by acpi ? */ + resource_list_for_each_entry(window, resources) + if (window->res->flags & IORESOURCE_BUS) { + found = true; + break; + } + + if (!found) + pci_add_resource(resources, &info->busn); + + list_for_each_entry(root_res, &info->resources, list) + pci_add_resource(resources, &root_res->res); + + return; + +default_resources: + /* + * We don't have any host bridge aperture information from the + * "native host bridge drivers," e.g., amd_bus or broadcom_bus, + * so fall back to the defaults historically used by pci_create_bus(). + */ + printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus); + pci_add_resource(resources, &ioport_resource); + pci_add_resource(resources, &iomem_resource); +} + +struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max, + int node, int link) +{ + struct pci_root_info *info; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + + if (!info) + return info; + + sprintf(info->name, "PCI Bus #%02x", bus_min); + + INIT_LIST_HEAD(&info->resources); + info->busn.name = info->name; + info->busn.start = bus_min; + info->busn.end = bus_max; + info->busn.flags = IORESOURCE_BUS; + info->node = node; + info->link = link; + + list_add_tail(&info->list, &pci_root_infos); + + return info; +} + +void update_res(struct pci_root_info *info, resource_size_t start, + resource_size_t end, unsigned long flags, int merge) +{ + struct resource *res; + struct pci_root_res *root_res; + + if (start > end) + return; + + if (start == MAX_RESOURCE) + return; + + if (!merge) + goto addit; + + /* try to merge it with old one */ + list_for_each_entry(root_res, &info->resources, list) { + resource_size_t final_start, final_end; + resource_size_t common_start, common_end; + + res = &root_res->res; + if (res->flags != flags) + continue; + + common_start = max(res->start, start); + common_end = min(res->end, end); + if (common_start > common_end + 1) + continue; + + final_start = min(res->start, start); + final_end = max(res->end, end); + + res->start = final_start; + res->end = final_end; + return; + } + +addit: + + /* need to add that */ + root_res = kzalloc(sizeof(*root_res), GFP_KERNEL); + if (!root_res) + return; + + res = &root_res->res; + res->name = info->name; + res->flags = flags; + res->start = start; + res->end = end; + + list_add_tail(&root_res->list, &info->resources); +} |