diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/pci/setup-bus.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r-- | drivers/pci/setup-bus.c | 752 |
1 files changed, 226 insertions, 526 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 6d3591d57ea..784da9d3602 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -25,13 +25,10 @@ | |||
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <linux/cache.h> | 26 | #include <linux/cache.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <asm-generic/pci-bridge.h> | ||
29 | #include "pci.h" | 28 | #include "pci.h" |
30 | 29 | ||
31 | unsigned int pci_flags; | 30 | struct resource_list_x { |
32 | 31 | struct resource_list_x *next; | |
33 | struct pci_dev_resource { | ||
34 | struct list_head list; | ||
35 | struct resource *res; | 32 | struct resource *res; |
36 | struct pci_dev *dev; | 33 | struct pci_dev *dev; |
37 | resource_size_t start; | 34 | resource_size_t start; |
@@ -41,14 +38,21 @@ struct pci_dev_resource { | |||
41 | unsigned long flags; | 38 | unsigned long flags; |
42 | }; | 39 | }; |
43 | 40 | ||
44 | static void free_list(struct list_head *head) | 41 | #define free_list(type, head) do { \ |
42 | struct type *list, *tmp; \ | ||
43 | for (list = (head)->next; list;) { \ | ||
44 | tmp = list; \ | ||
45 | list = list->next; \ | ||
46 | kfree(tmp); \ | ||
47 | } \ | ||
48 | (head)->next = NULL; \ | ||
49 | } while (0) | ||
50 | |||
51 | int pci_realloc_enable = 0; | ||
52 | #define pci_realloc_enabled() pci_realloc_enable | ||
53 | void pci_realloc(void) | ||
45 | { | 54 | { |
46 | struct pci_dev_resource *dev_res, *tmp; | 55 | pci_realloc_enable = 1; |
47 | |||
48 | list_for_each_entry_safe(dev_res, tmp, head, list) { | ||
49 | list_del(&dev_res->list); | ||
50 | kfree(dev_res); | ||
51 | } | ||
52 | } | 56 | } |
53 | 57 | ||
54 | /** | 58 | /** |
@@ -60,18 +64,21 @@ static void free_list(struct list_head *head) | |||
60 | * @add_size: additional size to be optionally added | 64 | * @add_size: additional size to be optionally added |
61 | * to the resource | 65 | * to the resource |
62 | */ | 66 | */ |
63 | static int add_to_list(struct list_head *head, | 67 | static void add_to_list(struct resource_list_x *head, |
64 | struct pci_dev *dev, struct resource *res, | 68 | struct pci_dev *dev, struct resource *res, |
65 | resource_size_t add_size, resource_size_t min_align) | 69 | resource_size_t add_size, resource_size_t min_align) |
66 | { | 70 | { |
67 | struct pci_dev_resource *tmp; | 71 | struct resource_list_x *list = head; |
72 | struct resource_list_x *ln = list->next; | ||
73 | struct resource_list_x *tmp; | ||
68 | 74 | ||
69 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); | 75 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); |
70 | if (!tmp) { | 76 | if (!tmp) { |
71 | pr_warning("add_to_list: kmalloc() failed!\n"); | 77 | pr_warning("add_to_list: kmalloc() failed!\n"); |
72 | return -ENOMEM; | 78 | return; |
73 | } | 79 | } |
74 | 80 | ||
81 | tmp->next = ln; | ||
75 | tmp->res = res; | 82 | tmp->res = res; |
76 | tmp->dev = dev; | 83 | tmp->dev = dev; |
77 | tmp->start = res->start; | 84 | tmp->start = res->start; |
@@ -79,100 +86,19 @@ static int add_to_list(struct list_head *head, | |||
79 | tmp->flags = res->flags; | 86 | tmp->flags = res->flags; |
80 | tmp->add_size = add_size; | 87 | tmp->add_size = add_size; |
81 | tmp->min_align = min_align; | 88 | tmp->min_align = min_align; |
82 | 89 | list->next = tmp; | |
83 | list_add(&tmp->list, head); | ||
84 | |||
85 | return 0; | ||
86 | } | 90 | } |
87 | 91 | ||
88 | static void remove_from_list(struct list_head *head, | 92 | static void add_to_failed_list(struct resource_list_x *head, |
89 | struct resource *res) | 93 | struct pci_dev *dev, struct resource *res) |
90 | { | 94 | { |
91 | struct pci_dev_resource *dev_res, *tmp; | 95 | add_to_list(head, dev, res, |
92 | 96 | 0 /* dont care */, | |
93 | list_for_each_entry_safe(dev_res, tmp, head, list) { | 97 | 0 /* dont care */); |
94 | if (dev_res->res == res) { | ||
95 | list_del(&dev_res->list); | ||
96 | kfree(dev_res); | ||
97 | break; | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | static resource_size_t get_res_add_size(struct list_head *head, | ||
103 | struct resource *res) | ||
104 | { | ||
105 | struct pci_dev_resource *dev_res; | ||
106 | |||
107 | list_for_each_entry(dev_res, head, list) { | ||
108 | if (dev_res->res == res) { | ||
109 | int idx = res - &dev_res->dev->resource[0]; | ||
110 | |||
111 | dev_printk(KERN_DEBUG, &dev_res->dev->dev, | ||
112 | "res[%d]=%pR get_res_add_size add_size %llx\n", | ||
113 | idx, dev_res->res, | ||
114 | (unsigned long long)dev_res->add_size); | ||
115 | |||
116 | return dev_res->add_size; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | /* Sort resources by alignment */ | ||
124 | static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) | ||
125 | { | ||
126 | int i; | ||
127 | |||
128 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { | ||
129 | struct resource *r; | ||
130 | struct pci_dev_resource *dev_res, *tmp; | ||
131 | resource_size_t r_align; | ||
132 | struct list_head *n; | ||
133 | |||
134 | r = &dev->resource[i]; | ||
135 | |||
136 | if (r->flags & IORESOURCE_PCI_FIXED) | ||
137 | continue; | ||
138 | |||
139 | if (!(r->flags) || r->parent) | ||
140 | continue; | ||
141 | |||
142 | r_align = pci_resource_alignment(dev, r); | ||
143 | if (!r_align) { | ||
144 | dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n", | ||
145 | i, r); | ||
146 | continue; | ||
147 | } | ||
148 | |||
149 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); | ||
150 | if (!tmp) | ||
151 | panic("pdev_sort_resources(): " | ||
152 | "kmalloc() failed!\n"); | ||
153 | tmp->res = r; | ||
154 | tmp->dev = dev; | ||
155 | |||
156 | /* fallback is smallest one or list is empty*/ | ||
157 | n = head; | ||
158 | list_for_each_entry(dev_res, head, list) { | ||
159 | resource_size_t align; | ||
160 | |||
161 | align = pci_resource_alignment(dev_res->dev, | ||
162 | dev_res->res); | ||
163 | |||
164 | if (r_align > align) { | ||
165 | n = &dev_res->list; | ||
166 | break; | ||
167 | } | ||
168 | } | ||
169 | /* Insert it just before n*/ | ||
170 | list_add_tail(&tmp->list, n); | ||
171 | } | ||
172 | } | 98 | } |
173 | 99 | ||
174 | static void __dev_sort_resources(struct pci_dev *dev, | 100 | static void __dev_sort_resources(struct pci_dev *dev, |
175 | struct list_head *head) | 101 | struct resource_list *head) |
176 | { | 102 | { |
177 | u16 class = dev->class >> 8; | 103 | u16 class = dev->class >> 8; |
178 | 104 | ||
@@ -210,54 +136,49 @@ static inline void reset_resource(struct resource *res) | |||
210 | * additional resources for the element, provided the element | 136 | * additional resources for the element, provided the element |
211 | * is in the head list. | 137 | * is in the head list. |
212 | */ | 138 | */ |
213 | static void reassign_resources_sorted(struct list_head *realloc_head, | 139 | static void reassign_resources_sorted(struct resource_list_x *realloc_head, |
214 | struct list_head *head) | 140 | struct resource_list *head) |
215 | { | 141 | { |
216 | struct resource *res; | 142 | struct resource *res; |
217 | struct pci_dev_resource *add_res, *tmp; | 143 | struct resource_list_x *list, *tmp, *prev; |
218 | struct pci_dev_resource *dev_res; | 144 | struct resource_list *hlist; |
219 | resource_size_t add_size; | 145 | resource_size_t add_size; |
220 | int idx; | 146 | int idx; |
221 | 147 | ||
222 | list_for_each_entry_safe(add_res, tmp, realloc_head, list) { | 148 | prev = realloc_head; |
223 | bool found_match = false; | 149 | for (list = realloc_head->next; list;) { |
224 | 150 | res = list->res; | |
225 | res = add_res->res; | ||
226 | /* skip resource that has been reset */ | 151 | /* skip resource that has been reset */ |
227 | if (!res->flags) | 152 | if (!res->flags) |
228 | goto out; | 153 | goto out; |
229 | 154 | ||
230 | /* skip this resource if not found in head list */ | 155 | /* skip this resource if not found in head list */ |
231 | list_for_each_entry(dev_res, head, list) { | 156 | for (hlist = head->next; hlist && hlist->res != res; |
232 | if (dev_res->res == res) { | 157 | hlist = hlist->next); |
233 | found_match = true; | 158 | if (!hlist) { /* just skip */ |
234 | break; | 159 | prev = list; |
235 | } | 160 | list = list->next; |
236 | } | ||
237 | if (!found_match)/* just skip */ | ||
238 | continue; | 161 | continue; |
162 | } | ||
239 | 163 | ||
240 | idx = res - &add_res->dev->resource[0]; | 164 | idx = res - &list->dev->resource[0]; |
241 | add_size = add_res->add_size; | 165 | add_size=list->add_size; |
242 | if (!resource_size(res)) { | 166 | if (!resource_size(res)) { |
243 | res->start = add_res->start; | 167 | res->start = list->start; |
244 | res->end = res->start + add_size - 1; | 168 | res->end = res->start + add_size - 1; |
245 | if (pci_assign_resource(add_res->dev, idx)) | 169 | if(pci_assign_resource(list->dev, idx)) |
246 | reset_resource(res); | 170 | reset_resource(res); |
247 | } else { | 171 | } else { |
248 | resource_size_t align = add_res->min_align; | 172 | resource_size_t align = list->min_align; |
249 | res->flags |= add_res->flags & | 173 | res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); |
250 | (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); | 174 | if (pci_reassign_resource(list->dev, idx, add_size, align)) |
251 | if (pci_reassign_resource(add_res->dev, idx, | 175 | dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n", |
252 | add_size, align)) | 176 | res); |
253 | dev_printk(KERN_DEBUG, &add_res->dev->dev, | ||
254 | "failed to add %llx res[%d]=%pR\n", | ||
255 | (unsigned long long)add_size, | ||
256 | idx, res); | ||
257 | } | 177 | } |
258 | out: | 178 | out: |
259 | list_del(&add_res->list); | 179 | tmp = list; |
260 | kfree(add_res); | 180 | prev->next = list = list->next; |
181 | kfree(tmp); | ||
261 | } | 182 | } |
262 | } | 183 | } |
263 | 184 | ||
@@ -265,105 +186,41 @@ out: | |||
265 | * assign_requested_resources_sorted() - satisfy resource requests | 186 | * assign_requested_resources_sorted() - satisfy resource requests |
266 | * | 187 | * |
267 | * @head : head of the list tracking requests for resources | 188 | * @head : head of the list tracking requests for resources |
268 | * @fail_head : head of the list tracking requests that could | 189 | * @failed_list : head of the list tracking requests that could |
269 | * not be allocated | 190 | * not be allocated |
270 | * | 191 | * |
271 | * Satisfy resource requests of each element in the list. Add | 192 | * Satisfy resource requests of each element in the list. Add |
272 | * requests that could not satisfied to the failed_list. | 193 | * requests that could not satisfied to the failed_list. |
273 | */ | 194 | */ |
274 | static void assign_requested_resources_sorted(struct list_head *head, | 195 | static void assign_requested_resources_sorted(struct resource_list *head, |
275 | struct list_head *fail_head) | 196 | struct resource_list_x *fail_head) |
276 | { | 197 | { |
277 | struct resource *res; | 198 | struct resource *res; |
278 | struct pci_dev_resource *dev_res; | 199 | struct resource_list *list; |
279 | int idx; | 200 | int idx; |
280 | 201 | ||
281 | list_for_each_entry(dev_res, head, list) { | 202 | for (list = head->next; list; list = list->next) { |
282 | res = dev_res->res; | 203 | res = list->res; |
283 | idx = res - &dev_res->dev->resource[0]; | 204 | idx = res - &list->dev->resource[0]; |
284 | if (resource_size(res) && | 205 | if (resource_size(res) && pci_assign_resource(list->dev, idx)) { |
285 | pci_assign_resource(dev_res->dev, idx)) { | 206 | if (fail_head && !pci_is_root_bus(list->dev->bus)) { |
286 | if (fail_head && !pci_is_root_bus(dev_res->dev->bus)) { | ||
287 | /* | 207 | /* |
288 | * if the failed res is for ROM BAR, and it will | 208 | * if the failed res is for ROM BAR, and it will |
289 | * be enabled later, don't add it to the list | 209 | * be enabled later, don't add it to the list |
290 | */ | 210 | */ |
291 | if (!((idx == PCI_ROM_RESOURCE) && | 211 | if (!((idx == PCI_ROM_RESOURCE) && |
292 | (!(res->flags & IORESOURCE_ROM_ENABLE)))) | 212 | (!(res->flags & IORESOURCE_ROM_ENABLE)))) |
293 | add_to_list(fail_head, | 213 | add_to_failed_list(fail_head, list->dev, res); |
294 | dev_res->dev, res, | ||
295 | 0 /* dont care */, | ||
296 | 0 /* dont care */); | ||
297 | } | 214 | } |
298 | reset_resource(res); | 215 | reset_resource(res); |
299 | } | 216 | } |
300 | } | 217 | } |
301 | } | 218 | } |
302 | 219 | ||
303 | static void __assign_resources_sorted(struct list_head *head, | 220 | static void __assign_resources_sorted(struct resource_list *head, |
304 | struct list_head *realloc_head, | 221 | struct resource_list_x *realloc_head, |
305 | struct list_head *fail_head) | 222 | struct resource_list_x *fail_head) |
306 | { | 223 | { |
307 | /* | ||
308 | * Should not assign requested resources at first. | ||
309 | * they could be adjacent, so later reassign can not reallocate | ||
310 | * them one by one in parent resource window. | ||
311 | * Try to assign requested + add_size at beginning | ||
312 | * if could do that, could get out early. | ||
313 | * if could not do that, we still try to assign requested at first, | ||
314 | * then try to reassign add_size for some resources. | ||
315 | */ | ||
316 | LIST_HEAD(save_head); | ||
317 | LIST_HEAD(local_fail_head); | ||
318 | struct pci_dev_resource *save_res; | ||
319 | struct pci_dev_resource *dev_res; | ||
320 | |||
321 | /* Check if optional add_size is there */ | ||
322 | if (!realloc_head || list_empty(realloc_head)) | ||
323 | goto requested_and_reassign; | ||
324 | |||
325 | /* Save original start, end, flags etc at first */ | ||
326 | list_for_each_entry(dev_res, head, list) { | ||
327 | if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) { | ||
328 | free_list(&save_head); | ||
329 | goto requested_and_reassign; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | /* Update res in head list with add_size in realloc_head list */ | ||
334 | list_for_each_entry(dev_res, head, list) | ||
335 | dev_res->res->end += get_res_add_size(realloc_head, | ||
336 | dev_res->res); | ||
337 | |||
338 | /* Try updated head list with add_size added */ | ||
339 | assign_requested_resources_sorted(head, &local_fail_head); | ||
340 | |||
341 | /* all assigned with add_size ? */ | ||
342 | if (list_empty(&local_fail_head)) { | ||
343 | /* Remove head list from realloc_head list */ | ||
344 | list_for_each_entry(dev_res, head, list) | ||
345 | remove_from_list(realloc_head, dev_res->res); | ||
346 | free_list(&save_head); | ||
347 | free_list(head); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | free_list(&local_fail_head); | ||
352 | /* Release assigned resource */ | ||
353 | list_for_each_entry(dev_res, head, list) | ||
354 | if (dev_res->res->parent) | ||
355 | release_resource(dev_res->res); | ||
356 | /* Restore start/end/flags from saved list */ | ||
357 | list_for_each_entry(save_res, &save_head, list) { | ||
358 | struct resource *res = save_res->res; | ||
359 | |||
360 | res->start = save_res->start; | ||
361 | res->end = save_res->end; | ||
362 | res->flags = save_res->flags; | ||
363 | } | ||
364 | free_list(&save_head); | ||
365 | |||
366 | requested_and_reassign: | ||
367 | /* Satisfy the must-have resource requests */ | 224 | /* Satisfy the must-have resource requests */ |
368 | assign_requested_resources_sorted(head, fail_head); | 225 | assign_requested_resources_sorted(head, fail_head); |
369 | 226 | ||
@@ -371,27 +228,28 @@ requested_and_reassign: | |||
371 | requests */ | 228 | requests */ |
372 | if (realloc_head) | 229 | if (realloc_head) |
373 | reassign_resources_sorted(realloc_head, head); | 230 | reassign_resources_sorted(realloc_head, head); |
374 | free_list(head); | 231 | free_list(resource_list, head); |
375 | } | 232 | } |
376 | 233 | ||
377 | static void pdev_assign_resources_sorted(struct pci_dev *dev, | 234 | static void pdev_assign_resources_sorted(struct pci_dev *dev, |
378 | struct list_head *add_head, | 235 | struct resource_list_x *fail_head) |
379 | struct list_head *fail_head) | ||
380 | { | 236 | { |
381 | LIST_HEAD(head); | 237 | struct resource_list head; |
382 | 238 | ||
239 | head.next = NULL; | ||
383 | __dev_sort_resources(dev, &head); | 240 | __dev_sort_resources(dev, &head); |
384 | __assign_resources_sorted(&head, add_head, fail_head); | 241 | __assign_resources_sorted(&head, NULL, fail_head); |
385 | 242 | ||
386 | } | 243 | } |
387 | 244 | ||
388 | static void pbus_assign_resources_sorted(const struct pci_bus *bus, | 245 | static void pbus_assign_resources_sorted(const struct pci_bus *bus, |
389 | struct list_head *realloc_head, | 246 | struct resource_list_x *realloc_head, |
390 | struct list_head *fail_head) | 247 | struct resource_list_x *fail_head) |
391 | { | 248 | { |
392 | struct pci_dev *dev; | 249 | struct pci_dev *dev; |
393 | LIST_HEAD(head); | 250 | struct resource_list head; |
394 | 251 | ||
252 | head.next = NULL; | ||
395 | list_for_each_entry(dev, &bus->devices, bus_list) | 253 | list_for_each_entry(dev, &bus->devices, bus_list) |
396 | __dev_sort_resources(dev, &head); | 254 | __dev_sort_resources(dev, &head); |
397 | 255 | ||
@@ -404,8 +262,8 @@ void pci_setup_cardbus(struct pci_bus *bus) | |||
404 | struct resource *res; | 262 | struct resource *res; |
405 | struct pci_bus_region region; | 263 | struct pci_bus_region region; |
406 | 264 | ||
407 | dev_info(&bridge->dev, "CardBus bridge to %pR\n", | 265 | dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n", |
408 | &bus->busn_res); | 266 | bus->secondary, bus->subordinate); |
409 | 267 | ||
410 | res = bus->resource[0]; | 268 | res = bus->resource[0]; |
411 | pcibios_resource_to_bus(bridge, ®ion, res); | 269 | pcibios_resource_to_bus(bridge, ®ion, res); |
@@ -469,23 +327,16 @@ static void pci_setup_bridge_io(struct pci_bus *bus) | |||
469 | struct pci_dev *bridge = bus->self; | 327 | struct pci_dev *bridge = bus->self; |
470 | struct resource *res; | 328 | struct resource *res; |
471 | struct pci_bus_region region; | 329 | struct pci_bus_region region; |
472 | unsigned long io_mask; | ||
473 | u8 io_base_lo, io_limit_lo; | ||
474 | u32 l, io_upper16; | 330 | u32 l, io_upper16; |
475 | 331 | ||
476 | io_mask = PCI_IO_RANGE_MASK; | ||
477 | if (bridge->io_window_1k) | ||
478 | io_mask = PCI_IO_1K_RANGE_MASK; | ||
479 | |||
480 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ | 332 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ |
481 | res = bus->resource[0]; | 333 | res = bus->resource[0]; |
482 | pcibios_resource_to_bus(bridge, ®ion, res); | 334 | pcibios_resource_to_bus(bridge, ®ion, res); |
483 | if (res->flags & IORESOURCE_IO) { | 335 | if (res->flags & IORESOURCE_IO) { |
484 | pci_read_config_dword(bridge, PCI_IO_BASE, &l); | 336 | pci_read_config_dword(bridge, PCI_IO_BASE, &l); |
485 | l &= 0xffff0000; | 337 | l &= 0xffff0000; |
486 | io_base_lo = (region.start >> 8) & io_mask; | 338 | l |= (region.start >> 8) & 0x00f0; |
487 | io_limit_lo = (region.end >> 8) & io_mask; | 339 | l |= region.end & 0xf000; |
488 | l |= ((u32) io_limit_lo << 8) | io_base_lo; | ||
489 | /* Set up upper 16 bits of I/O base/limit. */ | 340 | /* Set up upper 16 bits of I/O base/limit. */ |
490 | io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); | 341 | io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); |
491 | dev_info(&bridge->dev, " bridge window %pR\n", res); | 342 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
@@ -560,8 +411,8 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) | |||
560 | { | 411 | { |
561 | struct pci_dev *bridge = bus->self; | 412 | struct pci_dev *bridge = bus->self; |
562 | 413 | ||
563 | dev_info(&bridge->dev, "PCI bridge to %pR\n", | 414 | dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n", |
564 | &bus->busn_res); | 415 | bus->secondary, bus->subordinate); |
565 | 416 | ||
566 | if (type & IORESOURCE_IO) | 417 | if (type & IORESOURCE_IO) |
567 | pci_setup_bridge_io(bus); | 418 | pci_setup_bridge_io(bus); |
@@ -575,7 +426,7 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) | |||
575 | pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); | 426 | pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); |
576 | } | 427 | } |
577 | 428 | ||
578 | void pci_setup_bridge(struct pci_bus *bus) | 429 | static void pci_setup_bridge(struct pci_bus *bus) |
579 | { | 430 | { |
580 | unsigned long type = IORESOURCE_IO | IORESOURCE_MEM | | 431 | unsigned long type = IORESOURCE_IO | IORESOURCE_MEM | |
581 | IORESOURCE_PREFETCH; | 432 | IORESOURCE_PREFETCH; |
@@ -697,36 +548,18 @@ static resource_size_t calculate_memsize(resource_size_t size, | |||
697 | return size; | 548 | return size; |
698 | } | 549 | } |
699 | 550 | ||
700 | resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus, | 551 | static resource_size_t get_res_add_size(struct resource_list_x *realloc_head, |
701 | unsigned long type) | 552 | struct resource *res) |
702 | { | ||
703 | return 1; | ||
704 | } | ||
705 | |||
706 | #define PCI_P2P_DEFAULT_MEM_ALIGN 0x100000 /* 1MiB */ | ||
707 | #define PCI_P2P_DEFAULT_IO_ALIGN 0x1000 /* 4KiB */ | ||
708 | #define PCI_P2P_DEFAULT_IO_ALIGN_1K 0x400 /* 1KiB */ | ||
709 | |||
710 | static resource_size_t window_alignment(struct pci_bus *bus, | ||
711 | unsigned long type) | ||
712 | { | 553 | { |
713 | resource_size_t align = 1, arch_align; | 554 | struct resource_list_x *list; |
714 | 555 | ||
715 | if (type & IORESOURCE_MEM) | 556 | /* check if it is in realloc_head list */ |
716 | align = PCI_P2P_DEFAULT_MEM_ALIGN; | 557 | for (list = realloc_head->next; list && list->res != res; |
717 | else if (type & IORESOURCE_IO) { | 558 | list = list->next); |
718 | /* | 559 | if (list) |
719 | * Per spec, I/O windows are 4K-aligned, but some | 560 | return list->add_size; |
720 | * bridges have an extension to support 1K alignment. | ||
721 | */ | ||
722 | if (bus->self->io_window_1k) | ||
723 | align = PCI_P2P_DEFAULT_IO_ALIGN_1K; | ||
724 | else | ||
725 | align = PCI_P2P_DEFAULT_IO_ALIGN; | ||
726 | } | ||
727 | 561 | ||
728 | arch_align = pcibios_window_alignment(bus, type); | 562 | return 0; |
729 | return max(align, arch_align); | ||
730 | } | 563 | } |
731 | 564 | ||
732 | /** | 565 | /** |
@@ -738,23 +571,21 @@ static resource_size_t window_alignment(struct pci_bus *bus, | |||
738 | * @realloc_head : track the additional io window on this list | 571 | * @realloc_head : track the additional io window on this list |
739 | * | 572 | * |
740 | * Sizing the IO windows of the PCI-PCI bridge is trivial, | 573 | * Sizing the IO windows of the PCI-PCI bridge is trivial, |
741 | * since these windows have 1K or 4K granularity and the IO ranges | 574 | * since these windows have 4K granularity and the IO ranges |
742 | * of non-bridge PCI devices are limited to 256 bytes. | 575 | * of non-bridge PCI devices are limited to 256 bytes. |
743 | * We must be careful with the ISA aliasing though. | 576 | * We must be careful with the ISA aliasing though. |
744 | */ | 577 | */ |
745 | static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | 578 | static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, |
746 | resource_size_t add_size, struct list_head *realloc_head) | 579 | resource_size_t add_size, struct resource_list_x *realloc_head) |
747 | { | 580 | { |
748 | struct pci_dev *dev; | 581 | struct pci_dev *dev; |
749 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); | 582 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); |
750 | unsigned long size = 0, size0 = 0, size1 = 0; | 583 | unsigned long size = 0, size0 = 0, size1 = 0; |
751 | resource_size_t children_add_size = 0; | 584 | resource_size_t children_add_size = 0; |
752 | resource_size_t min_align, io_align, align; | ||
753 | 585 | ||
754 | if (!b_res) | 586 | if (!b_res) |
755 | return; | 587 | return; |
756 | 588 | ||
757 | io_align = min_align = window_alignment(bus, IORESOURCE_IO); | ||
758 | list_for_each_entry(dev, &bus->devices, bus_list) { | 589 | list_for_each_entry(dev, &bus->devices, bus_list) { |
759 | int i; | 590 | int i; |
760 | 591 | ||
@@ -772,66 +603,31 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | |||
772 | else | 603 | else |
773 | size1 += r_size; | 604 | size1 += r_size; |
774 | 605 | ||
775 | align = pci_resource_alignment(dev, r); | ||
776 | if (align > min_align) | ||
777 | min_align = align; | ||
778 | |||
779 | if (realloc_head) | 606 | if (realloc_head) |
780 | children_add_size += get_res_add_size(realloc_head, r); | 607 | children_add_size += get_res_add_size(realloc_head, r); |
781 | } | 608 | } |
782 | } | 609 | } |
783 | |||
784 | if (min_align > io_align) | ||
785 | min_align = io_align; | ||
786 | |||
787 | size0 = calculate_iosize(size, min_size, size1, | 610 | size0 = calculate_iosize(size, min_size, size1, |
788 | resource_size(b_res), min_align); | 611 | resource_size(b_res), 4096); |
789 | if (children_add_size > add_size) | 612 | if (children_add_size > add_size) |
790 | add_size = children_add_size; | 613 | add_size = children_add_size; |
791 | size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 : | 614 | size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 : |
792 | calculate_iosize(size, min_size, add_size + size1, | 615 | calculate_iosize(size, min_size+add_size, size1, |
793 | resource_size(b_res), min_align); | 616 | resource_size(b_res), 4096); |
794 | if (!size0 && !size1) { | 617 | if (!size0 && !size1) { |
795 | if (b_res->start || b_res->end) | 618 | if (b_res->start || b_res->end) |
796 | dev_info(&bus->self->dev, "disabling bridge window " | 619 | dev_info(&bus->self->dev, "disabling bridge window " |
797 | "%pR to %pR (unused)\n", b_res, | 620 | "%pR to [bus %02x-%02x] (unused)\n", b_res, |
798 | &bus->busn_res); | 621 | bus->secondary, bus->subordinate); |
799 | b_res->flags = 0; | 622 | b_res->flags = 0; |
800 | return; | 623 | return; |
801 | } | 624 | } |
802 | 625 | /* Alignment of the IO window is always 4K */ | |
803 | b_res->start = min_align; | 626 | b_res->start = 4096; |
804 | b_res->end = b_res->start + size0 - 1; | 627 | b_res->end = b_res->start + size0 - 1; |
805 | b_res->flags |= IORESOURCE_STARTALIGN; | 628 | b_res->flags |= IORESOURCE_STARTALIGN; |
806 | if (size1 > size0 && realloc_head) { | 629 | if (size1 > size0 && realloc_head) |
807 | add_to_list(realloc_head, bus->self, b_res, size1-size0, | 630 | add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096); |
808 | min_align); | ||
809 | dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " | ||
810 | "%pR to %pR add_size %lx\n", b_res, | ||
811 | &bus->busn_res, size1-size0); | ||
812 | } | ||
813 | } | ||
814 | |||
815 | static inline resource_size_t calculate_mem_align(resource_size_t *aligns, | ||
816 | int max_order) | ||
817 | { | ||
818 | resource_size_t align = 0; | ||
819 | resource_size_t min_align = 0; | ||
820 | int order; | ||
821 | |||
822 | for (order = 0; order <= max_order; order++) { | ||
823 | resource_size_t align1 = 1; | ||
824 | |||
825 | align1 <<= (order + 20); | ||
826 | |||
827 | if (!align) | ||
828 | min_align = align1; | ||
829 | else if (ALIGN(align + min_align, min_align) < align1) | ||
830 | min_align = align1 >> 1; | ||
831 | align += aligns[order]; | ||
832 | } | ||
833 | |||
834 | return min_align; | ||
835 | } | 631 | } |
836 | 632 | ||
837 | /** | 633 | /** |
@@ -848,7 +644,7 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns, | |||
848 | static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | 644 | static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, |
849 | unsigned long type, resource_size_t min_size, | 645 | unsigned long type, resource_size_t min_size, |
850 | resource_size_t add_size, | 646 | resource_size_t add_size, |
851 | struct list_head *realloc_head) | 647 | struct resource_list_x *realloc_head) |
852 | { | 648 | { |
853 | struct pci_dev *dev; | 649 | struct pci_dev *dev; |
854 | resource_size_t min_align, align, size, size0, size1; | 650 | resource_size_t min_align, align, size, size0, size1; |
@@ -913,32 +709,38 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
913 | children_add_size += get_res_add_size(realloc_head, r); | 709 | children_add_size += get_res_add_size(realloc_head, r); |
914 | } | 710 | } |
915 | } | 711 | } |
712 | align = 0; | ||
713 | min_align = 0; | ||
714 | for (order = 0; order <= max_order; order++) { | ||
715 | resource_size_t align1 = 1; | ||
716 | |||
717 | align1 <<= (order + 20); | ||
916 | 718 | ||
917 | min_align = calculate_mem_align(aligns, max_order); | 719 | if (!align) |
918 | min_align = max(min_align, window_alignment(bus, b_res->flags & mask)); | 720 | min_align = align1; |
721 | else if (ALIGN(align + min_align, min_align) < align1) | ||
722 | min_align = align1 >> 1; | ||
723 | align += aligns[order]; | ||
724 | } | ||
919 | size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); | 725 | size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); |
920 | if (children_add_size > add_size) | 726 | if (children_add_size > add_size) |
921 | add_size = children_add_size; | 727 | add_size = children_add_size; |
922 | size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 : | 728 | size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 : |
923 | calculate_memsize(size, min_size, add_size, | 729 | calculate_memsize(size, min_size+add_size, 0, |
924 | resource_size(b_res), min_align); | 730 | resource_size(b_res), min_align); |
925 | if (!size0 && !size1) { | 731 | if (!size0 && !size1) { |
926 | if (b_res->start || b_res->end) | 732 | if (b_res->start || b_res->end) |
927 | dev_info(&bus->self->dev, "disabling bridge window " | 733 | dev_info(&bus->self->dev, "disabling bridge window " |
928 | "%pR to %pR (unused)\n", b_res, | 734 | "%pR to [bus %02x-%02x] (unused)\n", b_res, |
929 | &bus->busn_res); | 735 | bus->secondary, bus->subordinate); |
930 | b_res->flags = 0; | 736 | b_res->flags = 0; |
931 | return 1; | 737 | return 1; |
932 | } | 738 | } |
933 | b_res->start = min_align; | 739 | b_res->start = min_align; |
934 | b_res->end = size0 + min_align - 1; | 740 | b_res->end = size0 + min_align - 1; |
935 | b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; | 741 | b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; |
936 | if (size1 > size0 && realloc_head) { | 742 | if (size1 > size0 && realloc_head) |
937 | add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); | 743 | add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); |
938 | dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " | ||
939 | "%pR to %pR add_size %llx\n", b_res, | ||
940 | &bus->busn_res, (unsigned long long)size1-size0); | ||
941 | } | ||
942 | return 1; | 744 | return 1; |
943 | } | 745 | } |
944 | 746 | ||
@@ -952,48 +754,25 @@ unsigned long pci_cardbus_resource_alignment(struct resource *res) | |||
952 | } | 754 | } |
953 | 755 | ||
954 | static void pci_bus_size_cardbus(struct pci_bus *bus, | 756 | static void pci_bus_size_cardbus(struct pci_bus *bus, |
955 | struct list_head *realloc_head) | 757 | struct resource_list_x *realloc_head) |
956 | { | 758 | { |
957 | struct pci_dev *bridge = bus->self; | 759 | struct pci_dev *bridge = bus->self; |
958 | struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; | 760 | struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; |
959 | resource_size_t b_res_3_size = pci_cardbus_mem_size * 2; | ||
960 | u16 ctrl; | 761 | u16 ctrl; |
961 | 762 | ||
962 | if (b_res[0].parent) | ||
963 | goto handle_b_res_1; | ||
964 | /* | 763 | /* |
965 | * Reserve some resources for CardBus. We reserve | 764 | * Reserve some resources for CardBus. We reserve |
966 | * a fixed amount of bus space for CardBus bridges. | 765 | * a fixed amount of bus space for CardBus bridges. |
967 | */ | 766 | */ |
968 | b_res[0].start = pci_cardbus_io_size; | 767 | b_res[0].start = 0; |
969 | b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1; | 768 | b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN; |
970 | b_res[0].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; | 769 | if (realloc_head) |
971 | if (realloc_head) { | 770 | add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, 0 /* dont care */); |
972 | b_res[0].end -= pci_cardbus_io_size; | ||
973 | add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, | ||
974 | pci_cardbus_io_size); | ||
975 | } | ||
976 | |||
977 | handle_b_res_1: | ||
978 | if (b_res[1].parent) | ||
979 | goto handle_b_res_2; | ||
980 | b_res[1].start = pci_cardbus_io_size; | ||
981 | b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1; | ||
982 | b_res[1].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; | ||
983 | if (realloc_head) { | ||
984 | b_res[1].end -= pci_cardbus_io_size; | ||
985 | add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, | ||
986 | pci_cardbus_io_size); | ||
987 | } | ||
988 | 771 | ||
989 | handle_b_res_2: | 772 | b_res[1].start = 0; |
990 | /* MEM1 must not be pref mmio */ | 773 | b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN; |
991 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | 774 | if (realloc_head) |
992 | if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) { | 775 | add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, 0 /* dont care */); |
993 | ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1; | ||
994 | pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl); | ||
995 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | ||
996 | } | ||
997 | 776 | ||
998 | /* | 777 | /* |
999 | * Check whether prefetchable memory is supported | 778 | * Check whether prefetchable memory is supported |
@@ -1006,46 +785,38 @@ handle_b_res_2: | |||
1006 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | 785 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); |
1007 | } | 786 | } |
1008 | 787 | ||
1009 | if (b_res[2].parent) | ||
1010 | goto handle_b_res_3; | ||
1011 | /* | 788 | /* |
1012 | * If we have prefetchable memory support, allocate | 789 | * If we have prefetchable memory support, allocate |
1013 | * two regions. Otherwise, allocate one region of | 790 | * two regions. Otherwise, allocate one region of |
1014 | * twice the size. | 791 | * twice the size. |
1015 | */ | 792 | */ |
1016 | if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { | 793 | if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { |
1017 | b_res[2].start = pci_cardbus_mem_size; | 794 | b_res[2].start = 0; |
1018 | b_res[2].end = b_res[2].start + pci_cardbus_mem_size - 1; | 795 | b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN; |
1019 | b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | | 796 | if (realloc_head) |
1020 | IORESOURCE_STARTALIGN; | 797 | add_to_list(realloc_head, bridge, b_res+2, pci_cardbus_mem_size, 0 /* dont care */); |
1021 | if (realloc_head) { | 798 | |
1022 | b_res[2].end -= pci_cardbus_mem_size; | 799 | b_res[3].start = 0; |
1023 | add_to_list(realloc_head, bridge, b_res+2, | 800 | b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN; |
1024 | pci_cardbus_mem_size, pci_cardbus_mem_size); | 801 | if (realloc_head) |
1025 | } | 802 | add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size, 0 /* dont care */); |
1026 | 803 | } else { | |
1027 | /* reduce that to half */ | 804 | b_res[3].start = 0; |
1028 | b_res_3_size = pci_cardbus_mem_size; | 805 | b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN; |
1029 | } | 806 | if (realloc_head) |
1030 | 807 | add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size * 2, 0 /* dont care */); | |
1031 | handle_b_res_3: | ||
1032 | if (b_res[3].parent) | ||
1033 | goto handle_done; | ||
1034 | b_res[3].start = pci_cardbus_mem_size; | ||
1035 | b_res[3].end = b_res[3].start + b_res_3_size - 1; | ||
1036 | b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN; | ||
1037 | if (realloc_head) { | ||
1038 | b_res[3].end -= b_res_3_size; | ||
1039 | add_to_list(realloc_head, bridge, b_res+3, b_res_3_size, | ||
1040 | pci_cardbus_mem_size); | ||
1041 | } | 808 | } |
1042 | 809 | ||
1043 | handle_done: | 810 | /* set the size of the resource to zero, so that the resource does not |
1044 | ; | 811 | * get assigned during required-resource allocation cycle but gets assigned |
812 | * during the optional-resource allocation cycle. | ||
813 | */ | ||
814 | b_res[0].start = b_res[1].start = b_res[2].start = b_res[3].start = 1; | ||
815 | b_res[0].end = b_res[1].end = b_res[2].end = b_res[3].end = 0; | ||
1045 | } | 816 | } |
1046 | 817 | ||
1047 | void __ref __pci_bus_size_bridges(struct pci_bus *bus, | 818 | void __ref __pci_bus_size_bridges(struct pci_bus *bus, |
1048 | struct list_head *realloc_head) | 819 | struct resource_list_x *realloc_head) |
1049 | { | 820 | { |
1050 | struct pci_dev *dev; | 821 | struct pci_dev *dev; |
1051 | unsigned long mask, prefmask; | 822 | unsigned long mask, prefmask; |
@@ -1087,8 +858,7 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus, | |||
1087 | * Follow thru | 858 | * Follow thru |
1088 | */ | 859 | */ |
1089 | default: | 860 | default: |
1090 | pbus_size_io(bus, realloc_head ? 0 : additional_io_size, | 861 | pbus_size_io(bus, 0, additional_io_size, realloc_head); |
1091 | additional_io_size, realloc_head); | ||
1092 | /* If the bridge supports prefetchable range, size it | 862 | /* If the bridge supports prefetchable range, size it |
1093 | separately. If it doesn't, or its prefetchable window | 863 | separately. If it doesn't, or its prefetchable window |
1094 | has already been allocated by arch code, try | 864 | has already been allocated by arch code, try |
@@ -1096,15 +866,11 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus, | |||
1096 | resources. */ | 866 | resources. */ |
1097 | mask = IORESOURCE_MEM; | 867 | mask = IORESOURCE_MEM; |
1098 | prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; | 868 | prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; |
1099 | if (pbus_size_mem(bus, prefmask, prefmask, | 869 | if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, realloc_head)) |
1100 | realloc_head ? 0 : additional_mem_size, | ||
1101 | additional_mem_size, realloc_head)) | ||
1102 | mask = prefmask; /* Success, size non-prefetch only. */ | 870 | mask = prefmask; /* Success, size non-prefetch only. */ |
1103 | else | 871 | else |
1104 | additional_mem_size += additional_mem_size; | 872 | additional_mem_size += additional_mem_size; |
1105 | pbus_size_mem(bus, mask, IORESOURCE_MEM, | 873 | pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, realloc_head); |
1106 | realloc_head ? 0 : additional_mem_size, | ||
1107 | additional_mem_size, realloc_head); | ||
1108 | break; | 874 | break; |
1109 | } | 875 | } |
1110 | } | 876 | } |
@@ -1116,8 +882,8 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
1116 | EXPORT_SYMBOL(pci_bus_size_bridges); | 882 | EXPORT_SYMBOL(pci_bus_size_bridges); |
1117 | 883 | ||
1118 | static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, | 884 | static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, |
1119 | struct list_head *realloc_head, | 885 | struct resource_list_x *realloc_head, |
1120 | struct list_head *fail_head) | 886 | struct resource_list_x *fail_head) |
1121 | { | 887 | { |
1122 | struct pci_bus *b; | 888 | struct pci_bus *b; |
1123 | struct pci_dev *dev; | 889 | struct pci_dev *dev; |
@@ -1156,19 +922,17 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus) | |||
1156 | EXPORT_SYMBOL(pci_bus_assign_resources); | 922 | EXPORT_SYMBOL(pci_bus_assign_resources); |
1157 | 923 | ||
1158 | static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, | 924 | static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, |
1159 | struct list_head *add_head, | 925 | struct resource_list_x *fail_head) |
1160 | struct list_head *fail_head) | ||
1161 | { | 926 | { |
1162 | struct pci_bus *b; | 927 | struct pci_bus *b; |
1163 | 928 | ||
1164 | pdev_assign_resources_sorted((struct pci_dev *)bridge, | 929 | pdev_assign_resources_sorted((struct pci_dev *)bridge, fail_head); |
1165 | add_head, fail_head); | ||
1166 | 930 | ||
1167 | b = bridge->subordinate; | 931 | b = bridge->subordinate; |
1168 | if (!b) | 932 | if (!b) |
1169 | return; | 933 | return; |
1170 | 934 | ||
1171 | __pci_bus_assign_resources(b, add_head, fail_head); | 935 | __pci_bus_assign_resources(b, NULL, fail_head); |
1172 | 936 | ||
1173 | switch (bridge->class >> 8) { | 937 | switch (bridge->class >> 8) { |
1174 | case PCI_CLASS_BRIDGE_PCI: | 938 | case PCI_CLASS_BRIDGE_PCI: |
@@ -1331,58 +1095,6 @@ static int __init pci_get_max_depth(void) | |||
1331 | return depth; | 1095 | return depth; |
1332 | } | 1096 | } |
1333 | 1097 | ||
1334 | /* | ||
1335 | * -1: undefined, will auto detect later | ||
1336 | * 0: disabled by user | ||
1337 | * 1: disabled by auto detect | ||
1338 | * 2: enabled by user | ||
1339 | * 3: enabled by auto detect | ||
1340 | */ | ||
1341 | enum enable_type { | ||
1342 | undefined = -1, | ||
1343 | user_disabled, | ||
1344 | auto_disabled, | ||
1345 | user_enabled, | ||
1346 | auto_enabled, | ||
1347 | }; | ||
1348 | |||
1349 | static enum enable_type pci_realloc_enable __initdata = undefined; | ||
1350 | void __init pci_realloc_get_opt(char *str) | ||
1351 | { | ||
1352 | if (!strncmp(str, "off", 3)) | ||
1353 | pci_realloc_enable = user_disabled; | ||
1354 | else if (!strncmp(str, "on", 2)) | ||
1355 | pci_realloc_enable = user_enabled; | ||
1356 | } | ||
1357 | static bool __init pci_realloc_enabled(void) | ||
1358 | { | ||
1359 | return pci_realloc_enable >= user_enabled; | ||
1360 | } | ||
1361 | |||
1362 | static void __init pci_realloc_detect(void) | ||
1363 | { | ||
1364 | #if defined(CONFIG_PCI_IOV) && defined(CONFIG_PCI_REALLOC_ENABLE_AUTO) | ||
1365 | struct pci_dev *dev = NULL; | ||
1366 | |||
1367 | if (pci_realloc_enable != undefined) | ||
1368 | return; | ||
1369 | |||
1370 | for_each_pci_dev(dev) { | ||
1371 | int i; | ||
1372 | |||
1373 | for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) { | ||
1374 | struct resource *r = &dev->resource[i]; | ||
1375 | |||
1376 | /* Not assigned, or rejected by kernel ? */ | ||
1377 | if (r->flags && !r->start) { | ||
1378 | pci_realloc_enable = auto_enabled; | ||
1379 | |||
1380 | return; | ||
1381 | } | ||
1382 | } | ||
1383 | } | ||
1384 | #endif | ||
1385 | } | ||
1386 | 1098 | ||
1387 | /* | 1099 | /* |
1388 | * first try will not touch pci bridge res | 1100 | * first try will not touch pci bridge res |
@@ -1393,57 +1105,59 @@ void __init | |||
1393 | pci_assign_unassigned_resources(void) | 1105 | pci_assign_unassigned_resources(void) |
1394 | { | 1106 | { |
1395 | struct pci_bus *bus; | 1107 | struct pci_bus *bus; |
1396 | LIST_HEAD(realloc_head); /* list of resources that | 1108 | struct resource_list_x realloc_list; /* list of resources that |
1397 | want additional resources */ | 1109 | want additional resources */ |
1398 | struct list_head *add_list = NULL; | ||
1399 | int tried_times = 0; | 1110 | int tried_times = 0; |
1400 | enum release_type rel_type = leaf_only; | 1111 | enum release_type rel_type = leaf_only; |
1401 | LIST_HEAD(fail_head); | 1112 | struct resource_list_x head, *list; |
1402 | struct pci_dev_resource *fail_res; | ||
1403 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | 1113 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | |
1404 | IORESOURCE_PREFETCH; | 1114 | IORESOURCE_PREFETCH; |
1405 | int pci_try_num = 1; | 1115 | unsigned long failed_type; |
1116 | int max_depth = pci_get_max_depth(); | ||
1117 | int pci_try_num; | ||
1406 | 1118 | ||
1407 | /* don't realloc if asked to do so */ | ||
1408 | pci_realloc_detect(); | ||
1409 | if (pci_realloc_enabled()) { | ||
1410 | int max_depth = pci_get_max_depth(); | ||
1411 | 1119 | ||
1412 | pci_try_num = max_depth + 1; | 1120 | head.next = NULL; |
1413 | printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n", | 1121 | realloc_list.next = NULL; |
1414 | max_depth, pci_try_num); | 1122 | |
1415 | } | 1123 | pci_try_num = max_depth + 1; |
1124 | printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n", | ||
1125 | max_depth, pci_try_num); | ||
1416 | 1126 | ||
1417 | again: | 1127 | again: |
1418 | /* | ||
1419 | * last try will use add_list, otherwise will try good to have as | ||
1420 | * must have, so can realloc parent bridge resource | ||
1421 | */ | ||
1422 | if (tried_times + 1 == pci_try_num) | ||
1423 | add_list = &realloc_head; | ||
1424 | /* Depth first, calculate sizes and alignments of all | 1128 | /* Depth first, calculate sizes and alignments of all |
1425 | subordinate buses. */ | 1129 | subordinate buses. */ |
1426 | list_for_each_entry(bus, &pci_root_buses, node) | 1130 | list_for_each_entry(bus, &pci_root_buses, node) |
1427 | __pci_bus_size_bridges(bus, add_list); | 1131 | __pci_bus_size_bridges(bus, &realloc_list); |
1428 | 1132 | ||
1429 | /* Depth last, allocate resources and update the hardware. */ | 1133 | /* Depth last, allocate resources and update the hardware. */ |
1430 | list_for_each_entry(bus, &pci_root_buses, node) | 1134 | list_for_each_entry(bus, &pci_root_buses, node) |
1431 | __pci_bus_assign_resources(bus, add_list, &fail_head); | 1135 | __pci_bus_assign_resources(bus, &realloc_list, &head); |
1432 | if (add_list) | 1136 | BUG_ON(realloc_list.next); |
1433 | BUG_ON(!list_empty(add_list)); | ||
1434 | tried_times++; | 1137 | tried_times++; |
1435 | 1138 | ||
1436 | /* any device complain? */ | 1139 | /* any device complain? */ |
1437 | if (list_empty(&fail_head)) | 1140 | if (!head.next) |
1438 | goto enable_and_dump; | 1141 | goto enable_and_dump; |
1439 | 1142 | ||
1440 | if (tried_times >= pci_try_num) { | 1143 | /* don't realloc if asked to do so */ |
1441 | if (pci_realloc_enable == undefined) | 1144 | if (!pci_realloc_enabled()) { |
1442 | printk(KERN_INFO "Some PCI device resources are unassigned, try booting with pci=realloc\n"); | 1145 | free_list(resource_list_x, &head); |
1443 | else if (pci_realloc_enable == auto_enabled) | 1146 | goto enable_and_dump; |
1444 | printk(KERN_INFO "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n"); | 1147 | } |
1445 | 1148 | ||
1446 | free_list(&fail_head); | 1149 | failed_type = 0; |
1150 | for (list = head.next; list;) { | ||
1151 | failed_type |= list->flags; | ||
1152 | list = list->next; | ||
1153 | } | ||
1154 | /* | ||
1155 | * io port are tight, don't try extra | ||
1156 | * or if reach the limit, don't want to try more | ||
1157 | */ | ||
1158 | failed_type &= type_mask; | ||
1159 | if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) { | ||
1160 | free_list(resource_list_x, &head); | ||
1447 | goto enable_and_dump; | 1161 | goto enable_and_dump; |
1448 | } | 1162 | } |
1449 | 1163 | ||
@@ -1458,23 +1172,25 @@ again: | |||
1458 | * Try to release leaf bridge's resources that doesn't fit resource of | 1172 | * Try to release leaf bridge's resources that doesn't fit resource of |
1459 | * child device under that bridge | 1173 | * child device under that bridge |
1460 | */ | 1174 | */ |
1461 | list_for_each_entry(fail_res, &fail_head, list) { | 1175 | for (list = head.next; list;) { |
1462 | bus = fail_res->dev->bus; | 1176 | bus = list->dev->bus; |
1463 | pci_bus_release_bridge_resources(bus, | 1177 | pci_bus_release_bridge_resources(bus, list->flags & type_mask, |
1464 | fail_res->flags & type_mask, | 1178 | rel_type); |
1465 | rel_type); | 1179 | list = list->next; |
1466 | } | 1180 | } |
1467 | /* restore size and flags */ | 1181 | /* restore size and flags */ |
1468 | list_for_each_entry(fail_res, &fail_head, list) { | 1182 | for (list = head.next; list;) { |
1469 | struct resource *res = fail_res->res; | 1183 | struct resource *res = list->res; |
1470 | 1184 | ||
1471 | res->start = fail_res->start; | 1185 | res->start = list->start; |
1472 | res->end = fail_res->end; | 1186 | res->end = list->end; |
1473 | res->flags = fail_res->flags; | 1187 | res->flags = list->flags; |
1474 | if (fail_res->dev->subordinate) | 1188 | if (list->dev->subordinate) |
1475 | res->flags = 0; | 1189 | res->flags = 0; |
1190 | |||
1191 | list = list->next; | ||
1476 | } | 1192 | } |
1477 | free_list(&fail_head); | 1193 | free_list(resource_list_x, &head); |
1478 | 1194 | ||
1479 | goto again; | 1195 | goto again; |
1480 | 1196 | ||
@@ -1491,27 +1207,26 @@ enable_and_dump: | |||
1491 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) | 1207 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) |
1492 | { | 1208 | { |
1493 | struct pci_bus *parent = bridge->subordinate; | 1209 | struct pci_bus *parent = bridge->subordinate; |
1494 | LIST_HEAD(add_list); /* list of resources that | ||
1495 | want additional resources */ | ||
1496 | int tried_times = 0; | 1210 | int tried_times = 0; |
1497 | LIST_HEAD(fail_head); | 1211 | struct resource_list_x head, *list; |
1498 | struct pci_dev_resource *fail_res; | ||
1499 | int retval; | 1212 | int retval; |
1500 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | 1213 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | |
1501 | IORESOURCE_PREFETCH; | 1214 | IORESOURCE_PREFETCH; |
1502 | 1215 | ||
1216 | head.next = NULL; | ||
1217 | |||
1503 | again: | 1218 | again: |
1504 | __pci_bus_size_bridges(parent, &add_list); | 1219 | pci_bus_size_bridges(parent); |
1505 | __pci_bridge_assign_resources(bridge, &add_list, &fail_head); | 1220 | __pci_bridge_assign_resources(bridge, &head); |
1506 | BUG_ON(!list_empty(&add_list)); | 1221 | |
1507 | tried_times++; | 1222 | tried_times++; |
1508 | 1223 | ||
1509 | if (list_empty(&fail_head)) | 1224 | if (!head.next) |
1510 | goto enable_all; | 1225 | goto enable_all; |
1511 | 1226 | ||
1512 | if (tried_times >= 2) { | 1227 | if (tried_times >= 2) { |
1513 | /* still fail, don't need to try more */ | 1228 | /* still fail, don't need to try more */ |
1514 | free_list(&fail_head); | 1229 | free_list(resource_list_x, &head); |
1515 | goto enable_all; | 1230 | goto enable_all; |
1516 | } | 1231 | } |
1517 | 1232 | ||
@@ -1522,24 +1237,27 @@ again: | |||
1522 | * Try to release leaf bridge's resources that doesn't fit resource of | 1237 | * Try to release leaf bridge's resources that doesn't fit resource of |
1523 | * child device under that bridge | 1238 | * child device under that bridge |
1524 | */ | 1239 | */ |
1525 | list_for_each_entry(fail_res, &fail_head, list) { | 1240 | for (list = head.next; list;) { |
1526 | struct pci_bus *bus = fail_res->dev->bus; | 1241 | struct pci_bus *bus = list->dev->bus; |
1527 | unsigned long flags = fail_res->flags; | 1242 | unsigned long flags = list->flags; |
1528 | 1243 | ||
1529 | pci_bus_release_bridge_resources(bus, flags & type_mask, | 1244 | pci_bus_release_bridge_resources(bus, flags & type_mask, |
1530 | whole_subtree); | 1245 | whole_subtree); |
1246 | list = list->next; | ||
1531 | } | 1247 | } |
1532 | /* restore size and flags */ | 1248 | /* restore size and flags */ |
1533 | list_for_each_entry(fail_res, &fail_head, list) { | 1249 | for (list = head.next; list;) { |
1534 | struct resource *res = fail_res->res; | 1250 | struct resource *res = list->res; |
1535 | 1251 | ||
1536 | res->start = fail_res->start; | 1252 | res->start = list->start; |
1537 | res->end = fail_res->end; | 1253 | res->end = list->end; |
1538 | res->flags = fail_res->flags; | 1254 | res->flags = list->flags; |
1539 | if (fail_res->dev->subordinate) | 1255 | if (list->dev->subordinate) |
1540 | res->flags = 0; | 1256 | res->flags = 0; |
1257 | |||
1258 | list = list->next; | ||
1541 | } | 1259 | } |
1542 | free_list(&fail_head); | 1260 | free_list(resource_list_x, &head); |
1543 | 1261 | ||
1544 | goto again; | 1262 | goto again; |
1545 | 1263 | ||
@@ -1549,21 +1267,3 @@ enable_all: | |||
1549 | pci_enable_bridges(parent); | 1267 | pci_enable_bridges(parent); |
1550 | } | 1268 | } |
1551 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); | 1269 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); |
1552 | |||
1553 | void pci_assign_unassigned_bus_resources(struct pci_bus *bus) | ||
1554 | { | ||
1555 | struct pci_dev *dev; | ||
1556 | LIST_HEAD(add_list); /* list of resources that | ||
1557 | want additional resources */ | ||
1558 | |||
1559 | down_read(&pci_bus_sem); | ||
1560 | list_for_each_entry(dev, &bus->devices, bus_list) | ||
1561 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | ||
1562 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | ||
1563 | if (dev->subordinate) | ||
1564 | __pci_bus_size_bridges(dev->subordinate, | ||
1565 | &add_list); | ||
1566 | up_read(&pci_bus_sem); | ||
1567 | __pci_bus_assign_resources(bus, &add_list, NULL); | ||
1568 | BUG_ON(!list_empty(&add_list)); | ||
1569 | } | ||