diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-01-21 05:08:27 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2012-02-14 11:44:55 -0500 |
commit | bdc4abecaeff30b3cc230b418a925999dda594c2 (patch) | |
tree | 560705372265c02af5c8e9738a0a2bcaae32bb02 /drivers/pci/setup-bus.c | |
parent | 2934a0de095f277a7bbc15a72ecf61af31a45163 (diff) |
PCI: Replace resource_list with generic list
So we can use helper functions for generic list. This makes the
resource re-allocation code much more readable.
-v2: Use list_add_tail instead of adding list_insert_before, Pointed out
by Linus.
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
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 | 374 |
1 files changed, 182 insertions, 192 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index b067a4cdce43..4c5509e3c75a 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -27,14 +27,14 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include "pci.h" | 28 | #include "pci.h" |
29 | 29 | ||
30 | struct resource_list { | 30 | struct pci_dev_resource { |
31 | struct resource_list *next; | 31 | struct list_head list; |
32 | struct resource *res; | 32 | struct resource *res; |
33 | struct pci_dev *dev; | 33 | struct pci_dev *dev; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | struct resource_list_x { | 36 | struct pci_dev_resource_x { |
37 | struct resource_list_x *next; | 37 | struct list_head list; |
38 | struct resource *res; | 38 | struct resource *res; |
39 | struct pci_dev *dev; | 39 | struct pci_dev *dev; |
40 | resource_size_t start; | 40 | resource_size_t start; |
@@ -44,14 +44,12 @@ struct resource_list_x { | |||
44 | unsigned long flags; | 44 | unsigned long flags; |
45 | }; | 45 | }; |
46 | 46 | ||
47 | #define free_list(type, head) do { \ | 47 | #define free_list(type, head) do { \ |
48 | struct type *list, *tmp; \ | 48 | struct type *dev_res, *tmp; \ |
49 | for (list = (head)->next; list;) { \ | 49 | list_for_each_entry_safe(dev_res, tmp, head, list) { \ |
50 | tmp = list; \ | 50 | list_del(&dev_res->list); \ |
51 | list = list->next; \ | 51 | kfree(dev_res); \ |
52 | kfree(tmp); \ | 52 | } \ |
53 | } \ | ||
54 | (head)->next = NULL; \ | ||
55 | } while (0) | 53 | } while (0) |
56 | 54 | ||
57 | int pci_realloc_enable = 0; | 55 | int pci_realloc_enable = 0; |
@@ -70,21 +68,18 @@ void pci_realloc(void) | |||
70 | * @add_size: additional size to be optionally added | 68 | * @add_size: additional size to be optionally added |
71 | * to the resource | 69 | * to the resource |
72 | */ | 70 | */ |
73 | static int add_to_list(struct resource_list_x *head, | 71 | static int add_to_list(struct list_head *head, |
74 | struct pci_dev *dev, struct resource *res, | 72 | struct pci_dev *dev, struct resource *res, |
75 | resource_size_t add_size, resource_size_t min_align) | 73 | resource_size_t add_size, resource_size_t min_align) |
76 | { | 74 | { |
77 | struct resource_list_x *list = head; | 75 | struct pci_dev_resource_x *tmp; |
78 | struct resource_list_x *ln = list->next; | ||
79 | struct resource_list_x *tmp; | ||
80 | 76 | ||
81 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); | 77 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); |
82 | if (!tmp) { | 78 | if (!tmp) { |
83 | pr_warning("add_to_list: kmalloc() failed!\n"); | 79 | pr_warning("add_to_list: kmalloc() failed!\n"); |
84 | return -ENOMEM; | 80 | return -ENOMEM; |
85 | } | 81 | } |
86 | 82 | ||
87 | tmp->next = ln; | ||
88 | tmp->res = res; | 83 | tmp->res = res; |
89 | tmp->dev = dev; | 84 | tmp->dev = dev; |
90 | tmp->start = res->start; | 85 | tmp->start = res->start; |
@@ -92,12 +87,13 @@ static int add_to_list(struct resource_list_x *head, | |||
92 | tmp->flags = res->flags; | 87 | tmp->flags = res->flags; |
93 | tmp->add_size = add_size; | 88 | tmp->add_size = add_size; |
94 | tmp->min_align = min_align; | 89 | tmp->min_align = min_align; |
95 | list->next = tmp; | 90 | |
91 | list_add(&tmp->list, head); | ||
96 | 92 | ||
97 | return 0; | 93 | return 0; |
98 | } | 94 | } |
99 | 95 | ||
100 | static void add_to_failed_list(struct resource_list_x *head, | 96 | static void add_to_failed_list(struct list_head *head, |
101 | struct pci_dev *dev, struct resource *res) | 97 | struct pci_dev *dev, struct resource *res) |
102 | { | 98 | { |
103 | add_to_list(head, dev, res, | 99 | add_to_list(head, dev, res, |
@@ -105,53 +101,48 @@ static void add_to_failed_list(struct resource_list_x *head, | |||
105 | 0 /* dont care */); | 101 | 0 /* dont care */); |
106 | } | 102 | } |
107 | 103 | ||
108 | static void remove_from_list(struct resource_list_x *realloc_head, | 104 | static void remove_from_list(struct list_head *realloc_head, |
109 | struct resource *res) | 105 | struct resource *res) |
110 | { | 106 | { |
111 | struct resource_list_x *prev, *tmp, *list; | 107 | struct pci_dev_resource_x *dev_res_x, *tmp; |
112 | 108 | ||
113 | prev = realloc_head; | 109 | list_for_each_entry_safe(dev_res_x, tmp, realloc_head, list) { |
114 | for (list = realloc_head->next; list;) { | 110 | if (dev_res_x->res == res) { |
115 | if (list->res != res) { | 111 | list_del(&dev_res_x->list); |
116 | prev = list; | 112 | kfree(dev_res_x); |
117 | list = list->next; | 113 | break; |
118 | continue; | ||
119 | } | 114 | } |
120 | tmp = list; | ||
121 | prev->next = list = list->next; | ||
122 | kfree(tmp); | ||
123 | } | 115 | } |
124 | } | 116 | } |
125 | 117 | ||
126 | static resource_size_t get_res_add_size(struct resource_list_x *realloc_head, | 118 | static resource_size_t get_res_add_size(struct list_head *realloc_head, |
127 | struct resource *res) | 119 | struct resource *res) |
128 | { | 120 | { |
129 | struct resource_list_x *list; | 121 | struct pci_dev_resource_x *dev_res_x; |
130 | 122 | ||
131 | /* check if it is in realloc_head list */ | 123 | list_for_each_entry(dev_res_x, realloc_head, list) { |
132 | for (list = realloc_head->next; list && list->res != res; | 124 | if (dev_res_x->res == res) { |
133 | list = list->next) | 125 | dev_printk(KERN_DEBUG, &dev_res_x->dev->dev, |
134 | ; | 126 | "%pR get_res_add_size add_size %llx\n", |
135 | 127 | dev_res_x->res, | |
136 | if (list) { | 128 | (unsigned long long)dev_res_x->add_size); |
137 | dev_printk(KERN_DEBUG, &list->dev->dev, | 129 | return dev_res_x->add_size; |
138 | "%pR get_res_add_size add_size %llx\n", | 130 | } |
139 | list->res, (unsigned long long)list->add_size); | ||
140 | return list->add_size; | ||
141 | } | 131 | } |
142 | 132 | ||
143 | return 0; | 133 | return 0; |
144 | } | 134 | } |
145 | 135 | ||
146 | /* Sort resources by alignment */ | 136 | /* Sort resources by alignment */ |
147 | static void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | 137 | static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) |
148 | { | 138 | { |
149 | int i; | 139 | int i; |
150 | 140 | ||
151 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { | 141 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { |
152 | struct resource *r; | 142 | struct resource *r; |
153 | struct resource_list *list, *tmp; | 143 | struct pci_dev_resource *dev_res, *tmp; |
154 | resource_size_t r_align; | 144 | resource_size_t r_align; |
145 | struct list_head *n; | ||
155 | 146 | ||
156 | r = &dev->resource[i]; | 147 | r = &dev->resource[i]; |
157 | 148 | ||
@@ -167,30 +158,34 @@ static void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | |||
167 | i, r); | 158 | i, r); |
168 | continue; | 159 | continue; |
169 | } | 160 | } |
170 | for (list = head; ; list = list->next) { | ||
171 | resource_size_t align = 0; | ||
172 | struct resource_list *ln = list->next; | ||
173 | 161 | ||
174 | if (ln) | 162 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); |
175 | align = pci_resource_alignment(ln->dev, ln->res); | 163 | if (!tmp) |
164 | panic("pdev_sort_resources(): " | ||
165 | "kmalloc() failed!\n"); | ||
166 | tmp->res = r; | ||
167 | tmp->dev = dev; | ||
168 | |||
169 | /* fallback is smallest one or list is empty*/ | ||
170 | n = head; | ||
171 | list_for_each_entry(dev_res, head, list) { | ||
172 | resource_size_t align; | ||
173 | |||
174 | align = pci_resource_alignment(dev_res->dev, | ||
175 | dev_res->res); | ||
176 | 176 | ||
177 | if (r_align > align) { | 177 | if (r_align > align) { |
178 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); | 178 | n = &dev_res->list; |
179 | if (!tmp) | ||
180 | panic("pdev_sort_resources(): " | ||
181 | "kmalloc() failed!\n"); | ||
182 | tmp->next = ln; | ||
183 | tmp->res = r; | ||
184 | tmp->dev = dev; | ||
185 | list->next = tmp; | ||
186 | break; | 179 | break; |
187 | } | 180 | } |
188 | } | 181 | } |
182 | /* Insert it just before n*/ | ||
183 | list_add_tail(&tmp->list, n); | ||
189 | } | 184 | } |
190 | } | 185 | } |
191 | 186 | ||
192 | static void __dev_sort_resources(struct pci_dev *dev, | 187 | static void __dev_sort_resources(struct pci_dev *dev, |
193 | struct resource_list *head) | 188 | struct list_head *head) |
194 | { | 189 | { |
195 | u16 class = dev->class >> 8; | 190 | u16 class = dev->class >> 8; |
196 | 191 | ||
@@ -228,49 +223,53 @@ static inline void reset_resource(struct resource *res) | |||
228 | * additional resources for the element, provided the element | 223 | * additional resources for the element, provided the element |
229 | * is in the head list. | 224 | * is in the head list. |
230 | */ | 225 | */ |
231 | static void reassign_resources_sorted(struct resource_list_x *realloc_head, | 226 | static void reassign_resources_sorted(struct list_head *realloc_head, |
232 | struct resource_list *head) | 227 | struct list_head *head) |
233 | { | 228 | { |
234 | struct resource *res; | 229 | struct resource *res; |
235 | struct resource_list_x *list, *tmp, *prev; | 230 | struct pci_dev_resource_x *dev_res_x, *tmp; |
236 | struct resource_list *hlist; | 231 | struct pci_dev_resource *dev_res; |
237 | resource_size_t add_size; | 232 | resource_size_t add_size; |
238 | int idx; | 233 | int idx; |
239 | 234 | ||
240 | prev = realloc_head; | 235 | list_for_each_entry_safe(dev_res_x, tmp, realloc_head, list) { |
241 | for (list = realloc_head->next; list;) { | 236 | bool found_match = false; |
242 | res = list->res; | 237 | |
238 | res = dev_res_x->res; | ||
243 | /* skip resource that has been reset */ | 239 | /* skip resource that has been reset */ |
244 | if (!res->flags) | 240 | if (!res->flags) |
245 | goto out; | 241 | goto out; |
246 | 242 | ||
247 | /* skip this resource if not found in head list */ | 243 | /* skip this resource if not found in head list */ |
248 | for (hlist = head->next; hlist && hlist->res != res; | 244 | list_for_each_entry(dev_res, head, list) { |
249 | hlist = hlist->next); | 245 | if (dev_res->res == res) { |
250 | if (!hlist) { /* just skip */ | 246 | found_match = true; |
251 | prev = list; | 247 | break; |
252 | list = list->next; | 248 | } |
253 | continue; | ||
254 | } | 249 | } |
250 | if (!found_match)/* just skip */ | ||
251 | continue; | ||
255 | 252 | ||
256 | idx = res - &list->dev->resource[0]; | 253 | idx = res - &dev_res_x->dev->resource[0]; |
257 | add_size=list->add_size; | 254 | add_size = dev_res_x->add_size; |
258 | if (!resource_size(res)) { | 255 | if (!resource_size(res)) { |
259 | res->start = list->start; | 256 | res->start = dev_res_x->start; |
260 | res->end = res->start + add_size - 1; | 257 | res->end = res->start + add_size - 1; |
261 | if(pci_assign_resource(list->dev, idx)) | 258 | if (pci_assign_resource(dev_res_x->dev, idx)) |
262 | reset_resource(res); | 259 | reset_resource(res); |
263 | } else { | 260 | } else { |
264 | resource_size_t align = list->min_align; | 261 | resource_size_t align = dev_res_x->min_align; |
265 | res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); | 262 | res->flags |= dev_res_x->flags & |
266 | if (pci_reassign_resource(list->dev, idx, add_size, align)) | 263 | (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); |
267 | dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n", | 264 | if (pci_reassign_resource(dev_res_x->dev, idx, |
265 | add_size, align)) | ||
266 | dev_printk(KERN_DEBUG, &dev_res_x->dev->dev, | ||
267 | "failed to add optional resources res=%pR\n", | ||
268 | res); | 268 | res); |
269 | } | 269 | } |
270 | out: | 270 | out: |
271 | tmp = list; | 271 | list_del(&dev_res_x->list); |
272 | prev->next = list = list->next; | 272 | kfree(dev_res_x); |
273 | kfree(tmp); | ||
274 | } | 273 | } |
275 | } | 274 | } |
276 | 275 | ||
@@ -284,34 +283,36 @@ out: | |||
284 | * Satisfy resource requests of each element in the list. Add | 283 | * Satisfy resource requests of each element in the list. Add |
285 | * requests that could not satisfied to the failed_list. | 284 | * requests that could not satisfied to the failed_list. |
286 | */ | 285 | */ |
287 | static void assign_requested_resources_sorted(struct resource_list *head, | 286 | static void assign_requested_resources_sorted(struct list_head *head, |
288 | struct resource_list_x *fail_head) | 287 | struct list_head *fail_head) |
289 | { | 288 | { |
290 | struct resource *res; | 289 | struct resource *res; |
291 | struct resource_list *list; | 290 | struct pci_dev_resource *dev_res; |
292 | int idx; | 291 | int idx; |
293 | 292 | ||
294 | for (list = head->next; list; list = list->next) { | 293 | list_for_each_entry(dev_res, head, list) { |
295 | res = list->res; | 294 | res = dev_res->res; |
296 | idx = res - &list->dev->resource[0]; | 295 | idx = res - &dev_res->dev->resource[0]; |
297 | if (resource_size(res) && pci_assign_resource(list->dev, idx)) { | 296 | if (resource_size(res) && |
298 | if (fail_head && !pci_is_root_bus(list->dev->bus)) { | 297 | pci_assign_resource(dev_res->dev, idx)) { |
298 | if (fail_head && !pci_is_root_bus(dev_res->dev->bus)) { | ||
299 | /* | 299 | /* |
300 | * if the failed res is for ROM BAR, and it will | 300 | * if the failed res is for ROM BAR, and it will |
301 | * be enabled later, don't add it to the list | 301 | * be enabled later, don't add it to the list |
302 | */ | 302 | */ |
303 | if (!((idx == PCI_ROM_RESOURCE) && | 303 | if (!((idx == PCI_ROM_RESOURCE) && |
304 | (!(res->flags & IORESOURCE_ROM_ENABLE)))) | 304 | (!(res->flags & IORESOURCE_ROM_ENABLE)))) |
305 | add_to_failed_list(fail_head, list->dev, res); | 305 | add_to_failed_list(fail_head, |
306 | dev_res->dev, res); | ||
306 | } | 307 | } |
307 | reset_resource(res); | 308 | reset_resource(res); |
308 | } | 309 | } |
309 | } | 310 | } |
310 | } | 311 | } |
311 | 312 | ||
312 | static void __assign_resources_sorted(struct resource_list *head, | 313 | static void __assign_resources_sorted(struct list_head *head, |
313 | struct resource_list_x *realloc_head, | 314 | struct list_head *realloc_head, |
314 | struct resource_list_x *fail_head) | 315 | struct list_head *fail_head) |
315 | { | 316 | { |
316 | /* | 317 | /* |
317 | * Should not assign requested resources at first. | 318 | * Should not assign requested resources at first. |
@@ -322,53 +323,55 @@ static void __assign_resources_sorted(struct resource_list *head, | |||
322 | * if could not do that, we still try to assign requested at first, | 323 | * if could not do that, we still try to assign requested at first, |
323 | * then try to reassign add_size for some resources. | 324 | * then try to reassign add_size for some resources. |
324 | */ | 325 | */ |
325 | struct resource_list_x save_head, local_fail_head, *list; | 326 | LIST_HEAD(save_head); |
326 | struct resource_list *l; | 327 | LIST_HEAD(local_fail_head); |
328 | struct pci_dev_resource_x *dev_res_x; | ||
329 | struct pci_dev_resource *dev_res; | ||
327 | 330 | ||
328 | /* Check if optional add_size is there */ | 331 | /* Check if optional add_size is there */ |
329 | if (!realloc_head || !realloc_head->next) | 332 | if (!realloc_head || list_empty(realloc_head)) |
330 | goto requested_and_reassign; | 333 | goto requested_and_reassign; |
331 | 334 | ||
332 | /* Save original start, end, flags etc at first */ | 335 | /* Save original start, end, flags etc at first */ |
333 | save_head.next = NULL; | 336 | list_for_each_entry(dev_res, head, list) { |
334 | for (l = head->next; l; l = l->next) | 337 | if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) { |
335 | if (add_to_list(&save_head, l->dev, l->res, 0, 0)) { | 338 | free_list(pci_dev_resource_x, &save_head); |
336 | free_list(resource_list_x, &save_head); | ||
337 | goto requested_and_reassign; | 339 | goto requested_and_reassign; |
338 | } | 340 | } |
341 | } | ||
339 | 342 | ||
340 | /* Update res in head list with add_size in realloc_head list */ | 343 | /* Update res in head list with add_size in realloc_head list */ |
341 | for (l = head->next; l; l = l->next) | 344 | list_for_each_entry(dev_res, head, list) |
342 | l->res->end += get_res_add_size(realloc_head, l->res); | 345 | dev_res->res->end += get_res_add_size(realloc_head, |
346 | dev_res->res); | ||
343 | 347 | ||
344 | /* Try updated head list with add_size added */ | 348 | /* Try updated head list with add_size added */ |
345 | local_fail_head.next = NULL; | ||
346 | assign_requested_resources_sorted(head, &local_fail_head); | 349 | assign_requested_resources_sorted(head, &local_fail_head); |
347 | 350 | ||
348 | /* all assigned with add_size ? */ | 351 | /* all assigned with add_size ? */ |
349 | if (!local_fail_head.next) { | 352 | if (list_empty(&local_fail_head)) { |
350 | /* Remove head list from realloc_head list */ | 353 | /* Remove head list from realloc_head list */ |
351 | for (l = head->next; l; l = l->next) | 354 | list_for_each_entry(dev_res, head, list) |
352 | remove_from_list(realloc_head, l->res); | 355 | remove_from_list(realloc_head, dev_res->res); |
353 | free_list(resource_list_x, &save_head); | 356 | free_list(pci_dev_resource_x, &save_head); |
354 | free_list(resource_list, head); | 357 | free_list(pci_dev_resource, head); |
355 | return; | 358 | return; |
356 | } | 359 | } |
357 | 360 | ||
358 | free_list(resource_list_x, &local_fail_head); | 361 | free_list(pci_dev_resource_x, &local_fail_head); |
359 | /* Release assigned resource */ | 362 | /* Release assigned resource */ |
360 | for (l = head->next; l; l = l->next) | 363 | list_for_each_entry(dev_res, head, list) |
361 | if (l->res->parent) | 364 | if (dev_res->res->parent) |
362 | release_resource(l->res); | 365 | release_resource(dev_res->res); |
363 | /* Restore start/end/flags from saved list */ | 366 | /* Restore start/end/flags from saved list */ |
364 | for (list = save_head.next; list; list = list->next) { | 367 | list_for_each_entry(dev_res_x, &save_head, list) { |
365 | struct resource *res = list->res; | 368 | struct resource *res = dev_res_x->res; |
366 | 369 | ||
367 | res->start = list->start; | 370 | res->start = dev_res_x->start; |
368 | res->end = list->end; | 371 | res->end = dev_res_x->end; |
369 | res->flags = list->flags; | 372 | res->flags = dev_res_x->flags; |
370 | } | 373 | } |
371 | free_list(resource_list_x, &save_head); | 374 | free_list(pci_dev_resource_x, &save_head); |
372 | 375 | ||
373 | requested_and_reassign: | 376 | requested_and_reassign: |
374 | /* Satisfy the must-have resource requests */ | 377 | /* Satisfy the must-have resource requests */ |
@@ -378,29 +381,27 @@ requested_and_reassign: | |||
378 | requests */ | 381 | requests */ |
379 | if (realloc_head) | 382 | if (realloc_head) |
380 | reassign_resources_sorted(realloc_head, head); | 383 | reassign_resources_sorted(realloc_head, head); |
381 | free_list(resource_list, head); | 384 | free_list(pci_dev_resource, head); |
382 | } | 385 | } |
383 | 386 | ||
384 | static void pdev_assign_resources_sorted(struct pci_dev *dev, | 387 | static void pdev_assign_resources_sorted(struct pci_dev *dev, |
385 | struct resource_list_x *add_head, | 388 | struct list_head *add_head, |
386 | struct resource_list_x *fail_head) | 389 | struct list_head *fail_head) |
387 | { | 390 | { |
388 | struct resource_list head; | 391 | LIST_HEAD(head); |
389 | 392 | ||
390 | head.next = NULL; | ||
391 | __dev_sort_resources(dev, &head); | 393 | __dev_sort_resources(dev, &head); |
392 | __assign_resources_sorted(&head, add_head, fail_head); | 394 | __assign_resources_sorted(&head, add_head, fail_head); |
393 | 395 | ||
394 | } | 396 | } |
395 | 397 | ||
396 | static void pbus_assign_resources_sorted(const struct pci_bus *bus, | 398 | static void pbus_assign_resources_sorted(const struct pci_bus *bus, |
397 | struct resource_list_x *realloc_head, | 399 | struct list_head *realloc_head, |
398 | struct resource_list_x *fail_head) | 400 | struct list_head *fail_head) |
399 | { | 401 | { |
400 | struct pci_dev *dev; | 402 | struct pci_dev *dev; |
401 | struct resource_list head; | 403 | LIST_HEAD(head); |
402 | 404 | ||
403 | head.next = NULL; | ||
404 | list_for_each_entry(dev, &bus->devices, bus_list) | 405 | list_for_each_entry(dev, &bus->devices, bus_list) |
405 | __dev_sort_resources(dev, &head); | 406 | __dev_sort_resources(dev, &head); |
406 | 407 | ||
@@ -713,7 +714,7 @@ static resource_size_t calculate_memsize(resource_size_t size, | |||
713 | * We must be careful with the ISA aliasing though. | 714 | * We must be careful with the ISA aliasing though. |
714 | */ | 715 | */ |
715 | static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | 716 | static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, |
716 | resource_size_t add_size, struct resource_list_x *realloc_head) | 717 | resource_size_t add_size, struct list_head *realloc_head) |
717 | { | 718 | { |
718 | struct pci_dev *dev; | 719 | struct pci_dev *dev; |
719 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); | 720 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); |
@@ -781,7 +782,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | |||
781 | static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | 782 | static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, |
782 | unsigned long type, resource_size_t min_size, | 783 | unsigned long type, resource_size_t min_size, |
783 | resource_size_t add_size, | 784 | resource_size_t add_size, |
784 | struct resource_list_x *realloc_head) | 785 | struct list_head *realloc_head) |
785 | { | 786 | { |
786 | struct pci_dev *dev; | 787 | struct pci_dev *dev; |
787 | resource_size_t min_align, align, size, size0, size1; | 788 | resource_size_t min_align, align, size, size0, size1; |
@@ -891,7 +892,7 @@ unsigned long pci_cardbus_resource_alignment(struct resource *res) | |||
891 | } | 892 | } |
892 | 893 | ||
893 | static void pci_bus_size_cardbus(struct pci_bus *bus, | 894 | static void pci_bus_size_cardbus(struct pci_bus *bus, |
894 | struct resource_list_x *realloc_head) | 895 | struct list_head *realloc_head) |
895 | { | 896 | { |
896 | struct pci_dev *bridge = bus->self; | 897 | struct pci_dev *bridge = bus->self; |
897 | struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; | 898 | struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; |
@@ -953,7 +954,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus, | |||
953 | } | 954 | } |
954 | 955 | ||
955 | void __ref __pci_bus_size_bridges(struct pci_bus *bus, | 956 | void __ref __pci_bus_size_bridges(struct pci_bus *bus, |
956 | struct resource_list_x *realloc_head) | 957 | struct list_head *realloc_head) |
957 | { | 958 | { |
958 | struct pci_dev *dev; | 959 | struct pci_dev *dev; |
959 | unsigned long mask, prefmask; | 960 | unsigned long mask, prefmask; |
@@ -1024,8 +1025,8 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
1024 | EXPORT_SYMBOL(pci_bus_size_bridges); | 1025 | EXPORT_SYMBOL(pci_bus_size_bridges); |
1025 | 1026 | ||
1026 | static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, | 1027 | static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, |
1027 | struct resource_list_x *realloc_head, | 1028 | struct list_head *realloc_head, |
1028 | struct resource_list_x *fail_head) | 1029 | struct list_head *fail_head) |
1029 | { | 1030 | { |
1030 | struct pci_bus *b; | 1031 | struct pci_bus *b; |
1031 | struct pci_dev *dev; | 1032 | struct pci_dev *dev; |
@@ -1064,8 +1065,8 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus) | |||
1064 | EXPORT_SYMBOL(pci_bus_assign_resources); | 1065 | EXPORT_SYMBOL(pci_bus_assign_resources); |
1065 | 1066 | ||
1066 | static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, | 1067 | static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, |
1067 | struct resource_list_x *add_head, | 1068 | struct list_head *add_head, |
1068 | struct resource_list_x *fail_head) | 1069 | struct list_head *fail_head) |
1069 | { | 1070 | { |
1070 | struct pci_bus *b; | 1071 | struct pci_bus *b; |
1071 | 1072 | ||
@@ -1249,20 +1250,18 @@ void __init | |||
1249 | pci_assign_unassigned_resources(void) | 1250 | pci_assign_unassigned_resources(void) |
1250 | { | 1251 | { |
1251 | struct pci_bus *bus; | 1252 | struct pci_bus *bus; |
1252 | struct resource_list_x realloc_list; /* list of resources that | 1253 | LIST_HEAD(realloc_head); /* list of resources that |
1253 | want additional resources */ | 1254 | want additional resources */ |
1254 | struct resource_list_x *add_list = NULL; | 1255 | struct list_head *add_list = NULL; |
1255 | int tried_times = 0; | 1256 | int tried_times = 0; |
1256 | enum release_type rel_type = leaf_only; | 1257 | enum release_type rel_type = leaf_only; |
1257 | struct resource_list_x head, *list; | 1258 | LIST_HEAD(fail_head); |
1259 | struct pci_dev_resource_x *dev_res_x; | ||
1258 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | 1260 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | |
1259 | IORESOURCE_PREFETCH; | 1261 | IORESOURCE_PREFETCH; |
1260 | unsigned long failed_type; | 1262 | unsigned long failed_type; |
1261 | int pci_try_num = 1; | 1263 | int pci_try_num = 1; |
1262 | 1264 | ||
1263 | head.next = NULL; | ||
1264 | realloc_list.next = NULL; | ||
1265 | |||
1266 | /* don't realloc if asked to do so */ | 1265 | /* don't realloc if asked to do so */ |
1267 | if (pci_realloc_enabled()) { | 1266 | if (pci_realloc_enabled()) { |
1268 | int max_depth = pci_get_max_depth(); | 1267 | int max_depth = pci_get_max_depth(); |
@@ -1278,7 +1277,7 @@ again: | |||
1278 | * must have, so can realloc parent bridge resource | 1277 | * must have, so can realloc parent bridge resource |
1279 | */ | 1278 | */ |
1280 | if (tried_times + 1 == pci_try_num) | 1279 | if (tried_times + 1 == pci_try_num) |
1281 | add_list = &realloc_list; | 1280 | add_list = &realloc_head; |
1282 | /* Depth first, calculate sizes and alignments of all | 1281 | /* Depth first, calculate sizes and alignments of all |
1283 | subordinate buses. */ | 1282 | subordinate buses. */ |
1284 | list_for_each_entry(bus, &pci_root_buses, node) | 1283 | list_for_each_entry(bus, &pci_root_buses, node) |
@@ -1286,27 +1285,26 @@ again: | |||
1286 | 1285 | ||
1287 | /* Depth last, allocate resources and update the hardware. */ | 1286 | /* Depth last, allocate resources and update the hardware. */ |
1288 | list_for_each_entry(bus, &pci_root_buses, node) | 1287 | list_for_each_entry(bus, &pci_root_buses, node) |
1289 | __pci_bus_assign_resources(bus, add_list, &head); | 1288 | __pci_bus_assign_resources(bus, add_list, &fail_head); |
1290 | if (add_list) | 1289 | if (add_list) |
1291 | BUG_ON(add_list->next); | 1290 | BUG_ON(!list_empty(add_list)); |
1292 | tried_times++; | 1291 | tried_times++; |
1293 | 1292 | ||
1294 | /* any device complain? */ | 1293 | /* any device complain? */ |
1295 | if (!head.next) | 1294 | if (list_empty(&fail_head)) |
1296 | goto enable_and_dump; | 1295 | goto enable_and_dump; |
1297 | 1296 | ||
1298 | failed_type = 0; | 1297 | failed_type = 0; |
1299 | for (list = head.next; list;) { | 1298 | list_for_each_entry(dev_res_x, &fail_head, list) |
1300 | failed_type |= list->flags; | 1299 | failed_type |= dev_res_x->flags; |
1301 | list = list->next; | 1300 | |
1302 | } | ||
1303 | /* | 1301 | /* |
1304 | * io port are tight, don't try extra | 1302 | * io port are tight, don't try extra |
1305 | * or if reach the limit, don't want to try more | 1303 | * or if reach the limit, don't want to try more |
1306 | */ | 1304 | */ |
1307 | failed_type &= type_mask; | 1305 | failed_type &= type_mask; |
1308 | if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) { | 1306 | if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) { |
1309 | free_list(resource_list_x, &head); | 1307 | free_list(pci_dev_resource_x, &fail_head); |
1310 | goto enable_and_dump; | 1308 | goto enable_and_dump; |
1311 | } | 1309 | } |
1312 | 1310 | ||
@@ -1321,25 +1319,23 @@ again: | |||
1321 | * Try to release leaf bridge's resources that doesn't fit resource of | 1319 | * Try to release leaf bridge's resources that doesn't fit resource of |
1322 | * child device under that bridge | 1320 | * child device under that bridge |
1323 | */ | 1321 | */ |
1324 | for (list = head.next; list;) { | 1322 | list_for_each_entry(dev_res_x, &fail_head, list) { |
1325 | bus = list->dev->bus; | 1323 | bus = dev_res_x->dev->bus; |
1326 | pci_bus_release_bridge_resources(bus, list->flags & type_mask, | 1324 | pci_bus_release_bridge_resources(bus, |
1327 | rel_type); | 1325 | dev_res_x->flags & type_mask, |
1328 | list = list->next; | 1326 | rel_type); |
1329 | } | 1327 | } |
1330 | /* restore size and flags */ | 1328 | /* restore size and flags */ |
1331 | for (list = head.next; list;) { | 1329 | list_for_each_entry(dev_res_x, &fail_head, list) { |
1332 | struct resource *res = list->res; | 1330 | struct resource *res = dev_res_x->res; |
1333 | 1331 | ||
1334 | res->start = list->start; | 1332 | res->start = dev_res_x->start; |
1335 | res->end = list->end; | 1333 | res->end = dev_res_x->end; |
1336 | res->flags = list->flags; | 1334 | res->flags = dev_res_x->flags; |
1337 | if (list->dev->subordinate) | 1335 | if (dev_res_x->dev->subordinate) |
1338 | res->flags = 0; | 1336 | res->flags = 0; |
1339 | |||
1340 | list = list->next; | ||
1341 | } | 1337 | } |
1342 | free_list(resource_list_x, &head); | 1338 | free_list(pci_dev_resource_x, &fail_head); |
1343 | 1339 | ||
1344 | goto again; | 1340 | goto again; |
1345 | 1341 | ||
@@ -1356,29 +1352,27 @@ enable_and_dump: | |||
1356 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) | 1352 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) |
1357 | { | 1353 | { |
1358 | struct pci_bus *parent = bridge->subordinate; | 1354 | struct pci_bus *parent = bridge->subordinate; |
1359 | struct resource_list_x add_list; /* list of resources that | 1355 | LIST_HEAD(add_list); /* list of resources that |
1360 | want additional resources */ | 1356 | want additional resources */ |
1361 | int tried_times = 0; | 1357 | int tried_times = 0; |
1362 | struct resource_list_x head, *list; | 1358 | LIST_HEAD(fail_head); |
1359 | struct pci_dev_resource_x *dev_res_x; | ||
1363 | int retval; | 1360 | int retval; |
1364 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | 1361 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | |
1365 | IORESOURCE_PREFETCH; | 1362 | IORESOURCE_PREFETCH; |
1366 | 1363 | ||
1367 | head.next = NULL; | ||
1368 | add_list.next = NULL; | ||
1369 | |||
1370 | again: | 1364 | again: |
1371 | __pci_bus_size_bridges(parent, &add_list); | 1365 | __pci_bus_size_bridges(parent, &add_list); |
1372 | __pci_bridge_assign_resources(bridge, &add_list, &head); | 1366 | __pci_bridge_assign_resources(bridge, &add_list, &fail_head); |
1373 | BUG_ON(add_list.next); | 1367 | BUG_ON(!list_empty(&add_list)); |
1374 | tried_times++; | 1368 | tried_times++; |
1375 | 1369 | ||
1376 | if (!head.next) | 1370 | if (list_empty(&fail_head)) |
1377 | goto enable_all; | 1371 | goto enable_all; |
1378 | 1372 | ||
1379 | if (tried_times >= 2) { | 1373 | if (tried_times >= 2) { |
1380 | /* still fail, don't need to try more */ | 1374 | /* still fail, don't need to try more */ |
1381 | free_list(resource_list_x, &head); | 1375 | free_list(pci_dev_resource_x, &fail_head); |
1382 | goto enable_all; | 1376 | goto enable_all; |
1383 | } | 1377 | } |
1384 | 1378 | ||
@@ -1389,27 +1383,24 @@ again: | |||
1389 | * Try to release leaf bridge's resources that doesn't fit resource of | 1383 | * Try to release leaf bridge's resources that doesn't fit resource of |
1390 | * child device under that bridge | 1384 | * child device under that bridge |
1391 | */ | 1385 | */ |
1392 | for (list = head.next; list;) { | 1386 | list_for_each_entry(dev_res_x, &fail_head, list) { |
1393 | struct pci_bus *bus = list->dev->bus; | 1387 | struct pci_bus *bus = dev_res_x->dev->bus; |
1394 | unsigned long flags = list->flags; | 1388 | unsigned long flags = dev_res_x->flags; |
1395 | 1389 | ||
1396 | pci_bus_release_bridge_resources(bus, flags & type_mask, | 1390 | pci_bus_release_bridge_resources(bus, flags & type_mask, |
1397 | whole_subtree); | 1391 | whole_subtree); |
1398 | list = list->next; | ||
1399 | } | 1392 | } |
1400 | /* restore size and flags */ | 1393 | /* restore size and flags */ |
1401 | for (list = head.next; list;) { | 1394 | list_for_each_entry(dev_res_x, &fail_head, list) { |
1402 | struct resource *res = list->res; | 1395 | struct resource *res = dev_res_x->res; |
1403 | 1396 | ||
1404 | res->start = list->start; | 1397 | res->start = dev_res_x->start; |
1405 | res->end = list->end; | 1398 | res->end = dev_res_x->end; |
1406 | res->flags = list->flags; | 1399 | res->flags = dev_res_x->flags; |
1407 | if (list->dev->subordinate) | 1400 | if (dev_res_x->dev->subordinate) |
1408 | res->flags = 0; | 1401 | res->flags = 0; |
1409 | |||
1410 | list = list->next; | ||
1411 | } | 1402 | } |
1412 | free_list(resource_list_x, &head); | 1403 | free_list(pci_dev_resource_x, &fail_head); |
1413 | 1404 | ||
1414 | goto again; | 1405 | goto again; |
1415 | 1406 | ||
@@ -1434,12 +1425,11 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus) | |||
1434 | { | 1425 | { |
1435 | unsigned int max; | 1426 | unsigned int max; |
1436 | struct pci_dev *dev; | 1427 | struct pci_dev *dev; |
1437 | struct resource_list_x add_list; /* list of resources that | 1428 | LIST_HEAD(add_list); /* list of resources that |
1438 | want additional resources */ | 1429 | want additional resources */ |
1439 | 1430 | ||
1440 | max = pci_scan_child_bus(bus); | 1431 | max = pci_scan_child_bus(bus); |
1441 | 1432 | ||
1442 | add_list.next = NULL; | ||
1443 | down_read(&pci_bus_sem); | 1433 | down_read(&pci_bus_sem); |
1444 | list_for_each_entry(dev, &bus->devices, bus_list) | 1434 | list_for_each_entry(dev, &bus->devices, bus_list) |
1445 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | 1435 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || |
@@ -1449,7 +1439,7 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus) | |||
1449 | &add_list); | 1439 | &add_list); |
1450 | up_read(&pci_bus_sem); | 1440 | up_read(&pci_bus_sem); |
1451 | __pci_bus_assign_resources(bus, &add_list, NULL); | 1441 | __pci_bus_assign_resources(bus, &add_list, NULL); |
1452 | BUG_ON(add_list.next); | 1442 | BUG_ON(!list_empty(&add_list)); |
1453 | 1443 | ||
1454 | pci_enable_bridges(bus); | 1444 | pci_enable_bridges(bus); |
1455 | pci_bus_add_devices(bus); | 1445 | pci_bus_add_devices(bus); |