aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/setup-bus.c
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2012-01-21 05:08:20 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2012-02-14 11:44:52 -0500
commit3e6e0d80941773a6d0ac94354b083b74967f06fb (patch)
treecbf597e9d4c6352baa606dc8c3b08dec92b8f40b /drivers/pci/setup-bus.c
parent1c372353e9c681b127f21030f8a0f0c2afd82429 (diff)
PCI: try to assign required+option size first
We found reassignment can not find a range for one resource, even if the total available range is large enough. bridge b1:02.0 will need 2M+3M bridge b1:03.0 will need 2M+3M so bridge b0:00.0 will get assigned: 4M : [f8000000-f83fffff] later is reassigned to 10M : [f8000000-f9ffffff] b1:02.0 is assigned to 2M : [f8000000-f81fffff] b1:03.0 is assigned to 2M : [f8200000-f83fffff] After that b1:03.0 get chance to be reassigned to [f8200000-f86fffff], but b1:02.0 will not have chance to expand, because b1:03.0 is using in middle one. [ 187.911401] pci 0000:b1:02.0: bridge window [mem 0x00100000-0x002fffff] to [bus b2-b2] add_size 300000 [ 187.920764] pci 0000:b1:03.0: bridge window [mem 0x00100000-0x002fffff] to [bus b3-b3] add_size 300000 [ 187.930129] pci 0000:b1:02.0: [mem 0x00100000-0x002fffff] get_res_add_size add_size 300000 [ 187.938500] pci 0000:b1:03.0: [mem 0x00100000-0x002fffff] get_res_add_size add_size 300000 [ 187.946857] pci 0000:b0:00.0: bridge window [mem 0x00100000-0x004fffff] to [bus b1-b3] add_size 600000 [ 187.956206] pci 0000:b0:00.0: BAR 14: assigned [mem 0xf8000000-0xf83fffff] [ 187.963102] pci 0000:b0:00.0: BAR 15: assigned [mem 0xf5000000-0xf51fffff pref] [ 187.970434] pci 0000:b0:00.0: BAR 14: reassigned [mem 0xf8000000-0xf89fffff] [ 187.977497] pci 0000:b1:02.0: BAR 14: assigned [mem 0xf8000000-0xf81fffff] [ 187.984383] pci 0000:b1:02.0: BAR 15: assigned [mem 0xf5000000-0xf50fffff pref] [ 187.991695] pci 0000:b1:03.0: BAR 14: assigned [mem 0xf8200000-0xf83fffff] [ 187.998576] pci 0000:b1:03.0: BAR 15: assigned [mem 0xf5100000-0xf51fffff pref] [ 188.005888] pci 0000:b1:03.0: BAR 14: reassigned [mem 0xf8200000-0xf86fffff] [ 188.012939] pci 0000:b1:02.0: BAR 14: can't assign mem (size 0x200000) [ 188.019471] pci 0000:b1:02.0: failed to add 300000 to res=[mem 0xf8000000-0xf81fffff] [ 188.027326] pci 0000:b2:00.0: reg 184: [mem 0x00000000-0x00003fff 64bit] [ 188.034071] pci 0000:b2:00.0: reg 18c: [mem 0x00000000-0x000fffff 64bit] [ 188.040795] pci 0000:b2:00.0: BAR 2: assigned [mem 0xf8000000-0xf80fffff 64bit] [ 188.048119] pci 0000:b2:00.0: BAR 2: set to [mem 0xf8000000-0xf80fffff 64bit] (PCI address [0xf8000000-0xf80fffff]) [ 188.058550] pci 0000:b2:00.0: BAR 6: assigned [mem 0xf5000000-0xf50fffff pref] [ 188.065802] pci 0000:b2:00.0: BAR 0: assigned [mem 0xf8100000-0xf8103fff 64bit] [ 188.073125] pci 0000:b2:00.0: BAR 0: set to [mem 0xf8100000-0xf8103fff 64bit] (PCI address [0xf8100000-0xf8103fff]) [ 188.083596] pci 0000:b2:00.0: reg 18c: [mem 0x00000000-0x000fffff 64bit] [ 188.090310] pci 0000:b2:00.0: BAR 9: can't assign mem (size 0x300000) [ 188.096773] pci 0000:b2:00.0: reg 184: [mem 0x00000000-0x00003fff 64bit] [ 188.103479] pci 0000:b2:00.0: BAR 7: assigned [mem 0xf8104000-0xf810ffff 64bit] [ 188.110801] pci 0000:b2:00.0: BAR 7: set to [mem 0xf8104000-0xf810ffff 64bit] (PCI address [0xf8104000-0xf810ffff]) [ 188.121256] pci 0000:b1:02.0: PCI bridge to [bus b2-b2] [ 188.126512] pci 0000:b1:02.0: bridge window [mem 0xf8000000-0xf81fffff] [ 188.133328] pci 0000:b1:02.0: bridge window [mem 0xf5000000-0xf50fffff pref] [ 188.140608] pci 0000:b3:00.0: reg 184: [mem 0x00000000-0x00003fff 64bit] [ 188.147341] pci 0000:b3:00.0: reg 18c: [mem 0x00000000-0x000fffff 64bit] [ 188.154076] pci 0000:b3:00.0: BAR 2: assigned [mem 0xf8200000-0xf82fffff 64bit] [ 188.161417] pci 0000:b3:00.0: BAR 2: set to [mem 0xf8200000-0xf82fffff 64bit] (PCI address [0xf8200000-0xf82fffff]) [ 188.171865] pci 0000:b3:00.0: BAR 6: assigned [mem 0xf5100000-0xf51fffff pref] [ 188.179090] pci 0000:b3:00.0: BAR 0: assigned [mem 0xf8300000-0xf8303fff 64bit] [ 188.186431] pci 0000:b3:00.0: BAR 0: set to [mem 0xf8300000-0xf8303fff 64bit] (PCI address [0xf8300000-0xf8303fff]) [ 188.196884] pci 0000:b3:00.0: reg 18c: [mem 0x00000000-0x000fffff 64bit] [ 188.203591] pci 0000:b3:00.0: BAR 9: assigned [mem 0xf8400000-0xf86fffff 64bit] [ 188.210909] pci 0000:b3:00.0: BAR 9: set to [mem 0xf8400000-0xf86fffff 64bit] (PCI address [0xf8400000-0xf86fffff]) [ 188.221379] pci 0000:b3:00.0: reg 184: [mem 0x00000000-0x00003fff 64bit] [ 188.228089] pci 0000:b3:00.0: BAR 7: assigned [mem 0xf8304000-0xf830ffff 64bit] [ 188.235407] pci 0000:b3:00.0: BAR 7: set to [mem 0xf8304000-0xf830ffff 64bit] (PCI address [0xf8304000-0xf830ffff]) [ 188.245843] pci 0000:b1:03.0: PCI bridge to [bus b3-b3] [ 188.251107] pci 0000:b1:03.0: bridge window [mem 0xf8200000-0xf86fffff] [ 188.257922] pci 0000:b1:03.0: bridge window [mem 0xf5100000-0xf51fffff pref] [ 188.265180] pci 0000:b0:00.0: PCI bridge to [bus b1-b3] [ 188.270443] pci 0000:b0:00.0: bridge window [mem 0xf8000000-0xf89fffff] [ 188.277250] pci 0000:b0:00.0: bridge window [mem 0xf5000000-0xf51fffff pref] [ 188.284512] pcieport 0000:80:02.2: PCI bridge to [bus b0-bf] [ 188.290184] pcieport 0000:80:02.2: bridge window [io 0xa000-0xbfff] [ 188.296735] pcieport 0000:80:02.2: bridge window [mem 0xf8000000-0xf8ffffff] [ 188.303963] pcieport 0000:80:02.2: bridge window [mem 0xf5000000-0xf5ffffff 64bit pref] Thus b2:00.0 BAR 9 does not get assigned... root cause: b1:02.0 can not be added more range, because b1:03.0 is just after it; no space between the required ranges. Solution: Try to assign required + optional all together at first, and if that fails, try again with just the required resources. -v2: seperate add_to_list change() to another patch according to Jesse. seperate get_res_add_size() moving to another patch according to Jesse. add !realloc_head->next check if the list is empty to bail early according to Jesse. Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r--drivers/pci/setup-bus.c83
1 files changed, 82 insertions, 1 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 75d43eb37842..7757c0026907 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -99,6 +99,24 @@ static void add_to_failed_list(struct resource_list_x *head,
99 0 /* dont care */); 99 0 /* dont care */);
100} 100}
101 101
102static void remove_from_list(struct resource_list_x *realloc_head,
103 struct resource *res)
104{
105 struct resource_list_x *prev, *tmp, *list;
106
107 prev = realloc_head;
108 for (list = realloc_head->next; list;) {
109 if (list->res != res) {
110 prev = list;
111 list = list->next;
112 continue;
113 }
114 tmp = list;
115 prev->next = list = list->next;
116 kfree(tmp);
117 }
118}
119
102static resource_size_t get_res_add_size(struct resource_list_x *realloc_head, 120static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
103 struct resource *res) 121 struct resource *res)
104{ 122{
@@ -108,8 +126,13 @@ static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
108 for (list = realloc_head->next; list && list->res != res; 126 for (list = realloc_head->next; list && list->res != res;
109 list = list->next) 127 list = list->next)
110 ; 128 ;
111 if (list) 129
130 if (list) {
131 dev_printk(KERN_DEBUG, &list->dev->dev,
132 "%pR get_res_add_size add_size %llx\n",
133 list->res, (unsigned long long)list->add_size);
112 return list->add_size; 134 return list->add_size;
135 }
113 136
114 return 0; 137 return 0;
115} 138}
@@ -238,6 +261,64 @@ static void __assign_resources_sorted(struct resource_list *head,
238 struct resource_list_x *realloc_head, 261 struct resource_list_x *realloc_head,
239 struct resource_list_x *fail_head) 262 struct resource_list_x *fail_head)
240{ 263{
264 /*
265 * Should not assign requested resources at first.
266 * they could be adjacent, so later reassign can not reallocate
267 * them one by one in parent resource window.
268 * Try to assign requested + add_size at begining
269 * if could do that, could get out early.
270 * if could not do that, we still try to assign requested at first,
271 * then try to reassign add_size for some resources.
272 */
273 struct resource_list_x save_head, local_fail_head, *list;
274 struct resource_list *l;
275
276 /* Check if optional add_size is there */
277 if (!realloc_head || !realloc_head->next)
278 goto requested_and_reassign;
279
280 /* Save original start, end, flags etc at first */
281 save_head.next = NULL;
282 for (l = head->next; l; l = l->next)
283 if (add_to_list(&save_head, l->dev, l->res, 0, 0)) {
284 free_list(resource_list_x, &save_head);
285 goto requested_and_reassign;
286 }
287
288 /* Update res in head list with add_size in realloc_head list */
289 for (l = head->next; l; l = l->next)
290 l->res->end += get_res_add_size(realloc_head, l->res);
291
292 /* Try updated head list with add_size added */
293 local_fail_head.next = NULL;
294 assign_requested_resources_sorted(head, &local_fail_head);
295
296 /* all assigned with add_size ? */
297 if (!local_fail_head.next) {
298 /* Remove head list from realloc_head list */
299 for (l = head->next; l; l = l->next)
300 remove_from_list(realloc_head, l->res);
301 free_list(resource_list_x, &save_head);
302 free_list(resource_list, head);
303 return;
304 }
305
306 free_list(resource_list_x, &local_fail_head);
307 /* Release assigned resource */
308 for (l = head->next; l; l = l->next)
309 if (l->res->parent)
310 release_resource(l->res);
311 /* Restore start/end/flags from saved list */
312 for (list = save_head.next; list; list = list->next) {
313 struct resource *res = list->res;
314
315 res->start = list->start;
316 res->end = list->end;
317 res->flags = list->flags;
318 }
319 free_list(resource_list_x, &save_head);
320
321requested_and_reassign:
241 /* Satisfy the must-have resource requests */ 322 /* Satisfy the must-have resource requests */
242 assign_requested_resources_sorted(head, fail_head); 323 assign_requested_resources_sorted(head, fail_head);
243 324