diff options
Diffstat (limited to 'arch/x86/pci/bus_numa.c')
-rw-r--r-- | arch/x86/pci/bus_numa.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c new file mode 100644 index 00000000..fd3f6551 --- /dev/null +++ b/arch/x86/pci/bus_numa.c @@ -0,0 +1,106 @@ +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/range.h> + +#include "bus_numa.h" + +int pci_root_num; +struct pci_root_info pci_root_info[PCI_ROOT_NR]; + +void x86_pci_root_bus_resources(int bus, struct list_head *resources) +{ + int i; + int j; + struct pci_root_info *info; + + if (!pci_root_num) + goto default_resources; + + for (i = 0; i < pci_root_num; i++) { + if (pci_root_info[i].bus_min == bus) + break; + } + + if (i == pci_root_num) + goto default_resources; + + printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n", + bus); + + info = &pci_root_info[i]; + for (j = 0; j < info->res_num; j++) { + struct resource *res; + struct resource *root; + + res = &info->res[j]; + pci_add_resource(resources, res); + if (res->flags & IORESOURCE_IO) + root = &ioport_resource; + else + root = &iomem_resource; + insert_resource(root, 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); +} + +void __devinit update_res(struct pci_root_info *info, resource_size_t start, + resource_size_t end, unsigned long flags, int merge) +{ + int i; + struct resource *res; + + if (start > end) + return; + + if (start == MAX_RESOURCE) + return; + + if (!merge) + goto addit; + + /* try to merge it with old one */ + for (i = 0; i < info->res_num; i++) { + resource_size_t final_start, final_end; + resource_size_t common_start, common_end; + + res = &info->res[i]; + 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 */ + if (info->res_num >= RES_NUM) + return; + + res = &info->res[info->res_num]; + res->name = info->name; + res->flags = flags; + res->start = start; + res->end = end; + res->child = NULL; + info->res_num++; +} |