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