xref: /linux/arch/x86/pci/bus_numa.c (revision 26b0d14106954ae46d2f4f7eec3481828a210f7d)
1 #include <linux/init.h>
2 #include <linux/pci.h>
3 #include <linux/range.h>
4 
5 #include "bus_numa.h"
6 
7 LIST_HEAD(pci_root_infos);
8 
9 static struct pci_root_info *x86_find_pci_root_info(int bus)
10 {
11 	struct pci_root_info *info;
12 
13 	if (list_empty(&pci_root_infos))
14 		return NULL;
15 
16 	list_for_each_entry(info, &pci_root_infos, list)
17 		if (info->bus_min == bus)
18 			return info;
19 
20 	return NULL;
21 }
22 
23 void x86_pci_root_bus_resources(int bus, struct list_head *resources)
24 {
25 	struct pci_root_info *info = x86_find_pci_root_info(bus);
26 	struct pci_root_res *root_res;
27 
28 	if (!info)
29 		goto default_resources;
30 
31 	printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n",
32 	       bus);
33 
34 	list_for_each_entry(root_res, &info->resources, list) {
35 		struct resource *res;
36 		struct resource *root;
37 
38 		res = &root_res->res;
39 		pci_add_resource(resources, res);
40 		if (res->flags & IORESOURCE_IO)
41 			root = &ioport_resource;
42 		else
43 			root = &iomem_resource;
44 		insert_resource(root, res);
45 	}
46 	return;
47 
48 default_resources:
49 	/*
50 	 * We don't have any host bridge aperture information from the
51 	 * "native host bridge drivers," e.g., amd_bus or broadcom_bus,
52 	 * so fall back to the defaults historically used by pci_create_bus().
53 	 */
54 	printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus);
55 	pci_add_resource(resources, &ioport_resource);
56 	pci_add_resource(resources, &iomem_resource);
57 }
58 
59 struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max,
60 						 int node, int link)
61 {
62 	struct pci_root_info *info;
63 
64 	info = kzalloc(sizeof(*info), GFP_KERNEL);
65 
66 	if (!info)
67 		return info;
68 
69 	INIT_LIST_HEAD(&info->resources);
70 	info->bus_min = bus_min;
71 	info->bus_max = bus_max;
72 	info->node = node;
73 	info->link = link;
74 
75 	list_add_tail(&info->list, &pci_root_infos);
76 
77 	return info;
78 }
79 
80 void __devinit update_res(struct pci_root_info *info, resource_size_t start,
81 			  resource_size_t end, unsigned long flags, int merge)
82 {
83 	struct resource *res;
84 	struct pci_root_res *root_res;
85 
86 	if (start > end)
87 		return;
88 
89 	if (start == MAX_RESOURCE)
90 		return;
91 
92 	if (!merge)
93 		goto addit;
94 
95 	/* try to merge it with old one */
96 	list_for_each_entry(root_res, &info->resources, list) {
97 		resource_size_t final_start, final_end;
98 		resource_size_t common_start, common_end;
99 
100 		res = &root_res->res;
101 		if (res->flags != flags)
102 			continue;
103 
104 		common_start = max(res->start, start);
105 		common_end = min(res->end, end);
106 		if (common_start > common_end + 1)
107 			continue;
108 
109 		final_start = min(res->start, start);
110 		final_end = max(res->end, end);
111 
112 		res->start = final_start;
113 		res->end = final_end;
114 		return;
115 	}
116 
117 addit:
118 
119 	/* need to add that */
120 	root_res = kzalloc(sizeof(*root_res), GFP_KERNEL);
121 	if (!root_res)
122 		return;
123 
124 	res = &root_res->res;
125 	res->name = info->name;
126 	res->flags = flags;
127 	res->start = start;
128 	res->end = end;
129 
130 	list_add_tail(&root_res->list, &info->resources);
131 }
132