diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-01-21 05:08:20 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2012-02-14 11:44:52 -0500 |
commit | 3e6e0d80941773a6d0ac94354b083b74967f06fb (patch) | |
tree | cbf597e9d4c6352baa606dc8c3b08dec92b8f40b /drivers/pci/setup-bus.c | |
parent | 1c372353e9c681b127f21030f8a0f0c2afd82429 (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.c | 83 |
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 | ||
102 | static 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 | |||
102 | static resource_size_t get_res_add_size(struct resource_list_x *realloc_head, | 120 | static 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 | |||
321 | requested_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 | ||