diff options
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r-- | drivers/pci/setup-bus.c | 455 |
1 files changed, 368 insertions, 87 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 66cb8f4cc5f4..9995842e45b5 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -33,11 +33,39 @@ struct resource_list_x { | |||
33 | struct pci_dev *dev; | 33 | struct pci_dev *dev; |
34 | resource_size_t start; | 34 | resource_size_t start; |
35 | resource_size_t end; | 35 | resource_size_t end; |
36 | resource_size_t add_size; | ||
36 | unsigned long flags; | 37 | unsigned long flags; |
37 | }; | 38 | }; |
38 | 39 | ||
39 | static void add_to_failed_list(struct resource_list_x *head, | 40 | #define free_list(type, head) do { \ |
40 | struct pci_dev *dev, struct resource *res) | 41 | struct type *list, *tmp; \ |
42 | for (list = (head)->next; list;) { \ | ||
43 | tmp = list; \ | ||
44 | list = list->next; \ | ||
45 | kfree(tmp); \ | ||
46 | } \ | ||
47 | (head)->next = NULL; \ | ||
48 | } while (0) | ||
49 | |||
50 | int pci_realloc_enable = 0; | ||
51 | #define pci_realloc_enabled() pci_realloc_enable | ||
52 | void pci_realloc(void) | ||
53 | { | ||
54 | pci_realloc_enable = 1; | ||
55 | } | ||
56 | |||
57 | /** | ||
58 | * add_to_list() - add a new resource tracker to the list | ||
59 | * @head: Head of the list | ||
60 | * @dev: device corresponding to which the resource | ||
61 | * belongs | ||
62 | * @res: The resource to be tracked | ||
63 | * @add_size: additional size to be optionally added | ||
64 | * to the resource | ||
65 | */ | ||
66 | static void add_to_list(struct resource_list_x *head, | ||
67 | struct pci_dev *dev, struct resource *res, | ||
68 | resource_size_t add_size) | ||
41 | { | 69 | { |
42 | struct resource_list_x *list = head; | 70 | struct resource_list_x *list = head; |
43 | struct resource_list_x *ln = list->next; | 71 | struct resource_list_x *ln = list->next; |
@@ -45,7 +73,7 @@ static void add_to_failed_list(struct resource_list_x *head, | |||
45 | 73 | ||
46 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); | 74 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); |
47 | if (!tmp) { | 75 | if (!tmp) { |
48 | pr_warning("add_to_failed_list: kmalloc() failed!\n"); | 76 | pr_warning("add_to_list: kmalloc() failed!\n"); |
49 | return; | 77 | return; |
50 | } | 78 | } |
51 | 79 | ||
@@ -55,20 +83,14 @@ static void add_to_failed_list(struct resource_list_x *head, | |||
55 | tmp->start = res->start; | 83 | tmp->start = res->start; |
56 | tmp->end = res->end; | 84 | tmp->end = res->end; |
57 | tmp->flags = res->flags; | 85 | tmp->flags = res->flags; |
86 | tmp->add_size = add_size; | ||
58 | list->next = tmp; | 87 | list->next = tmp; |
59 | } | 88 | } |
60 | 89 | ||
61 | static void free_failed_list(struct resource_list_x *head) | 90 | static void add_to_failed_list(struct resource_list_x *head, |
91 | struct pci_dev *dev, struct resource *res) | ||
62 | { | 92 | { |
63 | struct resource_list_x *list, *tmp; | 93 | add_to_list(head, dev, res, 0); |
64 | |||
65 | for (list = head->next; list;) { | ||
66 | tmp = list; | ||
67 | list = list->next; | ||
68 | kfree(tmp); | ||
69 | } | ||
70 | |||
71 | head->next = NULL; | ||
72 | } | 94 | } |
73 | 95 | ||
74 | static void __dev_sort_resources(struct pci_dev *dev, | 96 | static void __dev_sort_resources(struct pci_dev *dev, |
@@ -91,18 +113,88 @@ static void __dev_sort_resources(struct pci_dev *dev, | |||
91 | pdev_sort_resources(dev, head); | 113 | pdev_sort_resources(dev, head); |
92 | } | 114 | } |
93 | 115 | ||
94 | static void __assign_resources_sorted(struct resource_list *head, | 116 | static inline void reset_resource(struct resource *res) |
95 | struct resource_list_x *fail_head) | 117 | { |
118 | res->start = 0; | ||
119 | res->end = 0; | ||
120 | res->flags = 0; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * adjust_resources_sorted() - satisfy any additional resource requests | ||
125 | * | ||
126 | * @add_head : head of the list tracking requests requiring additional | ||
127 | * resources | ||
128 | * @head : head of the list tracking requests with allocated | ||
129 | * resources | ||
130 | * | ||
131 | * Walk through each element of the add_head and try to procure | ||
132 | * additional resources for the element, provided the element | ||
133 | * is in the head list. | ||
134 | */ | ||
135 | static void adjust_resources_sorted(struct resource_list_x *add_head, | ||
136 | struct resource_list *head) | ||
96 | { | 137 | { |
97 | struct resource *res; | 138 | struct resource *res; |
98 | struct resource_list *list, *tmp; | 139 | struct resource_list_x *list, *tmp, *prev; |
140 | struct resource_list *hlist; | ||
141 | resource_size_t add_size; | ||
99 | int idx; | 142 | int idx; |
100 | 143 | ||
101 | for (list = head->next; list;) { | 144 | prev = add_head; |
145 | for (list = add_head->next; list;) { | ||
102 | res = list->res; | 146 | res = list->res; |
147 | /* skip resource that has been reset */ | ||
148 | if (!res->flags) | ||
149 | goto out; | ||
150 | |||
151 | /* skip this resource if not found in head list */ | ||
152 | for (hlist = head->next; hlist && hlist->res != res; | ||
153 | hlist = hlist->next); | ||
154 | if (!hlist) { /* just skip */ | ||
155 | prev = list; | ||
156 | list = list->next; | ||
157 | continue; | ||
158 | } | ||
159 | |||
103 | idx = res - &list->dev->resource[0]; | 160 | idx = res - &list->dev->resource[0]; |
161 | add_size=list->add_size; | ||
162 | if (!resource_size(res) && add_size) { | ||
163 | res->end = res->start + add_size - 1; | ||
164 | if(pci_assign_resource(list->dev, idx)) | ||
165 | reset_resource(res); | ||
166 | } else if (add_size) { | ||
167 | adjust_resource(res, res->start, | ||
168 | resource_size(res) + add_size); | ||
169 | } | ||
170 | out: | ||
171 | tmp = list; | ||
172 | prev->next = list = list->next; | ||
173 | kfree(tmp); | ||
174 | } | ||
175 | } | ||
104 | 176 | ||
105 | if (pci_assign_resource(list->dev, idx)) { | 177 | /** |
178 | * assign_requested_resources_sorted() - satisfy resource requests | ||
179 | * | ||
180 | * @head : head of the list tracking requests for resources | ||
181 | * @failed_list : head of the list tracking requests that could | ||
182 | * not be allocated | ||
183 | * | ||
184 | * Satisfy resource requests of each element in the list. Add | ||
185 | * requests that could not satisfied to the failed_list. | ||
186 | */ | ||
187 | static void assign_requested_resources_sorted(struct resource_list *head, | ||
188 | struct resource_list_x *fail_head) | ||
189 | { | ||
190 | struct resource *res; | ||
191 | struct resource_list *list; | ||
192 | int idx; | ||
193 | |||
194 | for (list = head->next; list; list = list->next) { | ||
195 | res = list->res; | ||
196 | idx = res - &list->dev->resource[0]; | ||
197 | if (resource_size(res) && pci_assign_resource(list->dev, idx)) { | ||
106 | if (fail_head && !pci_is_root_bus(list->dev->bus)) { | 198 | if (fail_head && !pci_is_root_bus(list->dev->bus)) { |
107 | /* | 199 | /* |
108 | * if the failed res is for ROM BAR, and it will | 200 | * if the failed res is for ROM BAR, and it will |
@@ -112,16 +204,25 @@ static void __assign_resources_sorted(struct resource_list *head, | |||
112 | (!(res->flags & IORESOURCE_ROM_ENABLE)))) | 204 | (!(res->flags & IORESOURCE_ROM_ENABLE)))) |
113 | add_to_failed_list(fail_head, list->dev, res); | 205 | add_to_failed_list(fail_head, list->dev, res); |
114 | } | 206 | } |
115 | res->start = 0; | 207 | reset_resource(res); |
116 | res->end = 0; | ||
117 | res->flags = 0; | ||
118 | } | 208 | } |
119 | tmp = list; | ||
120 | list = list->next; | ||
121 | kfree(tmp); | ||
122 | } | 209 | } |
123 | } | 210 | } |
124 | 211 | ||
212 | static void __assign_resources_sorted(struct resource_list *head, | ||
213 | struct resource_list_x *add_head, | ||
214 | struct resource_list_x *fail_head) | ||
215 | { | ||
216 | /* Satisfy the must-have resource requests */ | ||
217 | assign_requested_resources_sorted(head, fail_head); | ||
218 | |||
219 | /* Try to satisfy any additional nice-to-have resource | ||
220 | requests */ | ||
221 | if (add_head) | ||
222 | adjust_resources_sorted(add_head, head); | ||
223 | free_list(resource_list, head); | ||
224 | } | ||
225 | |||
125 | static void pdev_assign_resources_sorted(struct pci_dev *dev, | 226 | static void pdev_assign_resources_sorted(struct pci_dev *dev, |
126 | struct resource_list_x *fail_head) | 227 | struct resource_list_x *fail_head) |
127 | { | 228 | { |
@@ -129,11 +230,12 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev, | |||
129 | 230 | ||
130 | head.next = NULL; | 231 | head.next = NULL; |
131 | __dev_sort_resources(dev, &head); | 232 | __dev_sort_resources(dev, &head); |
132 | __assign_resources_sorted(&head, fail_head); | 233 | __assign_resources_sorted(&head, NULL, fail_head); |
133 | 234 | ||
134 | } | 235 | } |
135 | 236 | ||
136 | static void pbus_assign_resources_sorted(const struct pci_bus *bus, | 237 | static void pbus_assign_resources_sorted(const struct pci_bus *bus, |
238 | struct resource_list_x *add_head, | ||
137 | struct resource_list_x *fail_head) | 239 | struct resource_list_x *fail_head) |
138 | { | 240 | { |
139 | struct pci_dev *dev; | 241 | struct pci_dev *dev; |
@@ -143,7 +245,7 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus, | |||
143 | list_for_each_entry(dev, &bus->devices, bus_list) | 245 | list_for_each_entry(dev, &bus->devices, bus_list) |
144 | __dev_sort_resources(dev, &head); | 246 | __dev_sort_resources(dev, &head); |
145 | 247 | ||
146 | __assign_resources_sorted(&head, fail_head); | 248 | __assign_resources_sorted(&head, add_head, fail_head); |
147 | } | 249 | } |
148 | 250 | ||
149 | void pci_setup_cardbus(struct pci_bus *bus) | 251 | void pci_setup_cardbus(struct pci_bus *bus) |
@@ -404,15 +506,62 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon | |||
404 | return NULL; | 506 | return NULL; |
405 | } | 507 | } |
406 | 508 | ||
407 | /* Sizing the IO windows of the PCI-PCI bridge is trivial, | 509 | static resource_size_t calculate_iosize(resource_size_t size, |
408 | since these windows have 4K granularity and the IO ranges | 510 | resource_size_t min_size, |
409 | of non-bridge PCI devices are limited to 256 bytes. | 511 | resource_size_t size1, |
410 | We must be careful with the ISA aliasing though. */ | 512 | resource_size_t old_size, |
411 | static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) | 513 | resource_size_t align) |
514 | { | ||
515 | if (size < min_size) | ||
516 | size = min_size; | ||
517 | if (old_size == 1 ) | ||
518 | old_size = 0; | ||
519 | /* To be fixed in 2.5: we should have sort of HAVE_ISA | ||
520 | flag in the struct pci_bus. */ | ||
521 | #if defined(CONFIG_ISA) || defined(CONFIG_EISA) | ||
522 | size = (size & 0xff) + ((size & ~0xffUL) << 2); | ||
523 | #endif | ||
524 | size = ALIGN(size + size1, align); | ||
525 | if (size < old_size) | ||
526 | size = old_size; | ||
527 | return size; | ||
528 | } | ||
529 | |||
530 | static resource_size_t calculate_memsize(resource_size_t size, | ||
531 | resource_size_t min_size, | ||
532 | resource_size_t size1, | ||
533 | resource_size_t old_size, | ||
534 | resource_size_t align) | ||
535 | { | ||
536 | if (size < min_size) | ||
537 | size = min_size; | ||
538 | if (old_size == 1 ) | ||
539 | old_size = 0; | ||
540 | if (size < old_size) | ||
541 | size = old_size; | ||
542 | size = ALIGN(size + size1, align); | ||
543 | return size; | ||
544 | } | ||
545 | |||
546 | /** | ||
547 | * pbus_size_io() - size the io window of a given bus | ||
548 | * | ||
549 | * @bus : the bus | ||
550 | * @min_size : the minimum io window that must to be allocated | ||
551 | * @add_size : additional optional io window | ||
552 | * @add_head : track the additional io window on this list | ||
553 | * | ||
554 | * Sizing the IO windows of the PCI-PCI bridge is trivial, | ||
555 | * since these windows have 4K granularity and the IO ranges | ||
556 | * of non-bridge PCI devices are limited to 256 bytes. | ||
557 | * We must be careful with the ISA aliasing though. | ||
558 | */ | ||
559 | static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | ||
560 | resource_size_t add_size, struct resource_list_x *add_head) | ||
412 | { | 561 | { |
413 | struct pci_dev *dev; | 562 | struct pci_dev *dev; |
414 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); | 563 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); |
415 | unsigned long size = 0, size1 = 0, old_size; | 564 | unsigned long size = 0, size0 = 0, size1 = 0; |
416 | 565 | ||
417 | if (!b_res) | 566 | if (!b_res) |
418 | return; | 567 | return; |
@@ -435,20 +584,12 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) | |||
435 | size1 += r_size; | 584 | size1 += r_size; |
436 | } | 585 | } |
437 | } | 586 | } |
438 | if (size < min_size) | 587 | size0 = calculate_iosize(size, min_size, size1, |
439 | size = min_size; | 588 | resource_size(b_res), 4096); |
440 | old_size = resource_size(b_res); | 589 | size1 = (!add_head || (add_head && !add_size)) ? size0 : |
441 | if (old_size == 1) | 590 | calculate_iosize(size, min_size+add_size, size1, |
442 | old_size = 0; | 591 | resource_size(b_res), 4096); |
443 | /* To be fixed in 2.5: we should have sort of HAVE_ISA | 592 | if (!size0 && !size1) { |
444 | flag in the struct pci_bus. */ | ||
445 | #if defined(CONFIG_ISA) || defined(CONFIG_EISA) | ||
446 | size = (size & 0xff) + ((size & ~0xffUL) << 2); | ||
447 | #endif | ||
448 | size = ALIGN(size + size1, 4096); | ||
449 | if (size < old_size) | ||
450 | size = old_size; | ||
451 | if (!size) { | ||
452 | if (b_res->start || b_res->end) | 593 | if (b_res->start || b_res->end) |
453 | dev_info(&bus->self->dev, "disabling bridge window " | 594 | dev_info(&bus->self->dev, "disabling bridge window " |
454 | "%pR to [bus %02x-%02x] (unused)\n", b_res, | 595 | "%pR to [bus %02x-%02x] (unused)\n", b_res, |
@@ -458,17 +599,30 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) | |||
458 | } | 599 | } |
459 | /* Alignment of the IO window is always 4K */ | 600 | /* Alignment of the IO window is always 4K */ |
460 | b_res->start = 4096; | 601 | b_res->start = 4096; |
461 | b_res->end = b_res->start + size - 1; | 602 | b_res->end = b_res->start + size0 - 1; |
462 | b_res->flags |= IORESOURCE_STARTALIGN; | 603 | b_res->flags |= IORESOURCE_STARTALIGN; |
604 | if (size1 > size0 && add_head) | ||
605 | add_to_list(add_head, bus->self, b_res, size1-size0); | ||
463 | } | 606 | } |
464 | 607 | ||
465 | /* Calculate the size of the bus and minimal alignment which | 608 | /** |
466 | guarantees that all child resources fit in this size. */ | 609 | * pbus_size_mem() - size the memory window of a given bus |
610 | * | ||
611 | * @bus : the bus | ||
612 | * @min_size : the minimum memory window that must to be allocated | ||
613 | * @add_size : additional optional memory window | ||
614 | * @add_head : track the additional memory window on this list | ||
615 | * | ||
616 | * Calculate the size of the bus and minimal alignment which | ||
617 | * guarantees that all child resources fit in this size. | ||
618 | */ | ||
467 | static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | 619 | static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, |
468 | unsigned long type, resource_size_t min_size) | 620 | unsigned long type, resource_size_t min_size, |
621 | resource_size_t add_size, | ||
622 | struct resource_list_x *add_head) | ||
469 | { | 623 | { |
470 | struct pci_dev *dev; | 624 | struct pci_dev *dev; |
471 | resource_size_t min_align, align, size, old_size; | 625 | resource_size_t min_align, align, size, size0, size1; |
472 | resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ | 626 | resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ |
473 | int order, max_order; | 627 | int order, max_order; |
474 | struct resource *b_res = find_free_bus_resource(bus, type); | 628 | struct resource *b_res = find_free_bus_resource(bus, type); |
@@ -516,14 +670,6 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
516 | mem64_mask &= r->flags & IORESOURCE_MEM_64; | 670 | mem64_mask &= r->flags & IORESOURCE_MEM_64; |
517 | } | 671 | } |
518 | } | 672 | } |
519 | if (size < min_size) | ||
520 | size = min_size; | ||
521 | old_size = resource_size(b_res); | ||
522 | if (old_size == 1) | ||
523 | old_size = 0; | ||
524 | if (size < old_size) | ||
525 | size = old_size; | ||
526 | |||
527 | align = 0; | 673 | align = 0; |
528 | min_align = 0; | 674 | min_align = 0; |
529 | for (order = 0; order <= max_order; order++) { | 675 | for (order = 0; order <= max_order; order++) { |
@@ -537,8 +683,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
537 | min_align = align1 >> 1; | 683 | min_align = align1 >> 1; |
538 | align += aligns[order]; | 684 | align += aligns[order]; |
539 | } | 685 | } |
540 | size = ALIGN(size, min_align); | 686 | size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); |
541 | if (!size) { | 687 | size1 = (!add_head || (add_head && !add_size)) ? size0 : |
688 | calculate_memsize(size, min_size+add_size, 0, | ||
689 | resource_size(b_res), min_align); | ||
690 | if (!size0 && !size1) { | ||
542 | if (b_res->start || b_res->end) | 691 | if (b_res->start || b_res->end) |
543 | dev_info(&bus->self->dev, "disabling bridge window " | 692 | dev_info(&bus->self->dev, "disabling bridge window " |
544 | "%pR to [bus %02x-%02x] (unused)\n", b_res, | 693 | "%pR to [bus %02x-%02x] (unused)\n", b_res, |
@@ -547,9 +696,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
547 | return 1; | 696 | return 1; |
548 | } | 697 | } |
549 | b_res->start = min_align; | 698 | b_res->start = min_align; |
550 | b_res->end = size + min_align - 1; | 699 | b_res->end = size0 + min_align - 1; |
551 | b_res->flags |= IORESOURCE_STARTALIGN; | 700 | b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; |
552 | b_res->flags |= mem64_mask; | 701 | if (size1 > size0 && add_head) |
702 | add_to_list(add_head, bus->self, b_res, size1-size0); | ||
553 | return 1; | 703 | return 1; |
554 | } | 704 | } |
555 | 705 | ||
@@ -602,11 +752,12 @@ static void pci_bus_size_cardbus(struct pci_bus *bus) | |||
602 | } | 752 | } |
603 | } | 753 | } |
604 | 754 | ||
605 | void __ref pci_bus_size_bridges(struct pci_bus *bus) | 755 | void __ref __pci_bus_size_bridges(struct pci_bus *bus, |
756 | struct resource_list_x *add_head) | ||
606 | { | 757 | { |
607 | struct pci_dev *dev; | 758 | struct pci_dev *dev; |
608 | unsigned long mask, prefmask; | 759 | unsigned long mask, prefmask; |
609 | resource_size_t min_mem_size = 0, min_io_size = 0; | 760 | resource_size_t additional_mem_size = 0, additional_io_size = 0; |
610 | 761 | ||
611 | list_for_each_entry(dev, &bus->devices, bus_list) { | 762 | list_for_each_entry(dev, &bus->devices, bus_list) { |
612 | struct pci_bus *b = dev->subordinate; | 763 | struct pci_bus *b = dev->subordinate; |
@@ -620,7 +771,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
620 | 771 | ||
621 | case PCI_CLASS_BRIDGE_PCI: | 772 | case PCI_CLASS_BRIDGE_PCI: |
622 | default: | 773 | default: |
623 | pci_bus_size_bridges(b); | 774 | __pci_bus_size_bridges(b, add_head); |
624 | break; | 775 | break; |
625 | } | 776 | } |
626 | } | 777 | } |
@@ -637,11 +788,14 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
637 | case PCI_CLASS_BRIDGE_PCI: | 788 | case PCI_CLASS_BRIDGE_PCI: |
638 | pci_bridge_check_ranges(bus); | 789 | pci_bridge_check_ranges(bus); |
639 | if (bus->self->is_hotplug_bridge) { | 790 | if (bus->self->is_hotplug_bridge) { |
640 | min_io_size = pci_hotplug_io_size; | 791 | additional_io_size = pci_hotplug_io_size; |
641 | min_mem_size = pci_hotplug_mem_size; | 792 | additional_mem_size = pci_hotplug_mem_size; |
642 | } | 793 | } |
794 | /* | ||
795 | * Follow thru | ||
796 | */ | ||
643 | default: | 797 | default: |
644 | pbus_size_io(bus, min_io_size); | 798 | pbus_size_io(bus, 0, additional_io_size, add_head); |
645 | /* If the bridge supports prefetchable range, size it | 799 | /* If the bridge supports prefetchable range, size it |
646 | separately. If it doesn't, or its prefetchable window | 800 | separately. If it doesn't, or its prefetchable window |
647 | has already been allocated by arch code, try | 801 | has already been allocated by arch code, try |
@@ -649,30 +803,36 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) | |||
649 | resources. */ | 803 | resources. */ |
650 | mask = IORESOURCE_MEM; | 804 | mask = IORESOURCE_MEM; |
651 | prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; | 805 | prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; |
652 | if (pbus_size_mem(bus, prefmask, prefmask, min_mem_size)) | 806 | if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, add_head)) |
653 | mask = prefmask; /* Success, size non-prefetch only. */ | 807 | mask = prefmask; /* Success, size non-prefetch only. */ |
654 | else | 808 | else |
655 | min_mem_size += min_mem_size; | 809 | additional_mem_size += additional_mem_size; |
656 | pbus_size_mem(bus, mask, IORESOURCE_MEM, min_mem_size); | 810 | pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, add_head); |
657 | break; | 811 | break; |
658 | } | 812 | } |
659 | } | 813 | } |
814 | |||
815 | void __ref pci_bus_size_bridges(struct pci_bus *bus) | ||
816 | { | ||
817 | __pci_bus_size_bridges(bus, NULL); | ||
818 | } | ||
660 | EXPORT_SYMBOL(pci_bus_size_bridges); | 819 | EXPORT_SYMBOL(pci_bus_size_bridges); |
661 | 820 | ||
662 | static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, | 821 | static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, |
822 | struct resource_list_x *add_head, | ||
663 | struct resource_list_x *fail_head) | 823 | struct resource_list_x *fail_head) |
664 | { | 824 | { |
665 | struct pci_bus *b; | 825 | struct pci_bus *b; |
666 | struct pci_dev *dev; | 826 | struct pci_dev *dev; |
667 | 827 | ||
668 | pbus_assign_resources_sorted(bus, fail_head); | 828 | pbus_assign_resources_sorted(bus, add_head, fail_head); |
669 | 829 | ||
670 | list_for_each_entry(dev, &bus->devices, bus_list) { | 830 | list_for_each_entry(dev, &bus->devices, bus_list) { |
671 | b = dev->subordinate; | 831 | b = dev->subordinate; |
672 | if (!b) | 832 | if (!b) |
673 | continue; | 833 | continue; |
674 | 834 | ||
675 | __pci_bus_assign_resources(b, fail_head); | 835 | __pci_bus_assign_resources(b, add_head, fail_head); |
676 | 836 | ||
677 | switch (dev->class >> 8) { | 837 | switch (dev->class >> 8) { |
678 | case PCI_CLASS_BRIDGE_PCI: | 838 | case PCI_CLASS_BRIDGE_PCI: |
@@ -694,7 +854,7 @@ static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, | |||
694 | 854 | ||
695 | void __ref pci_bus_assign_resources(const struct pci_bus *bus) | 855 | void __ref pci_bus_assign_resources(const struct pci_bus *bus) |
696 | { | 856 | { |
697 | __pci_bus_assign_resources(bus, NULL); | 857 | __pci_bus_assign_resources(bus, NULL, NULL); |
698 | } | 858 | } |
699 | EXPORT_SYMBOL(pci_bus_assign_resources); | 859 | EXPORT_SYMBOL(pci_bus_assign_resources); |
700 | 860 | ||
@@ -709,7 +869,7 @@ static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, | |||
709 | if (!b) | 869 | if (!b) |
710 | return; | 870 | return; |
711 | 871 | ||
712 | __pci_bus_assign_resources(b, fail_head); | 872 | __pci_bus_assign_resources(b, NULL, fail_head); |
713 | 873 | ||
714 | switch (bridge->class >> 8) { | 874 | switch (bridge->class >> 8) { |
715 | case PCI_CLASS_BRIDGE_PCI: | 875 | case PCI_CLASS_BRIDGE_PCI: |
@@ -838,26 +998,147 @@ static void pci_bus_dump_resources(struct pci_bus *bus) | |||
838 | } | 998 | } |
839 | } | 999 | } |
840 | 1000 | ||
1001 | static int __init pci_bus_get_depth(struct pci_bus *bus) | ||
1002 | { | ||
1003 | int depth = 0; | ||
1004 | struct pci_dev *dev; | ||
1005 | |||
1006 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
1007 | int ret; | ||
1008 | struct pci_bus *b = dev->subordinate; | ||
1009 | if (!b) | ||
1010 | continue; | ||
1011 | |||
1012 | ret = pci_bus_get_depth(b); | ||
1013 | if (ret + 1 > depth) | ||
1014 | depth = ret + 1; | ||
1015 | } | ||
1016 | |||
1017 | return depth; | ||
1018 | } | ||
1019 | static int __init pci_get_max_depth(void) | ||
1020 | { | ||
1021 | int depth = 0; | ||
1022 | struct pci_bus *bus; | ||
1023 | |||
1024 | list_for_each_entry(bus, &pci_root_buses, node) { | ||
1025 | int ret; | ||
1026 | |||
1027 | ret = pci_bus_get_depth(bus); | ||
1028 | if (ret > depth) | ||
1029 | depth = ret; | ||
1030 | } | ||
1031 | |||
1032 | return depth; | ||
1033 | } | ||
1034 | |||
1035 | |||
1036 | /* | ||
1037 | * first try will not touch pci bridge res | ||
1038 | * second and later try will clear small leaf bridge res | ||
1039 | * will stop till to the max deepth if can not find good one | ||
1040 | */ | ||
841 | void __init | 1041 | void __init |
842 | pci_assign_unassigned_resources(void) | 1042 | pci_assign_unassigned_resources(void) |
843 | { | 1043 | { |
844 | struct pci_bus *bus; | 1044 | struct pci_bus *bus; |
1045 | struct resource_list_x add_list; /* list of resources that | ||
1046 | want additional resources */ | ||
1047 | int tried_times = 0; | ||
1048 | enum release_type rel_type = leaf_only; | ||
1049 | struct resource_list_x head, *list; | ||
1050 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | ||
1051 | IORESOURCE_PREFETCH; | ||
1052 | unsigned long failed_type; | ||
1053 | int max_depth = pci_get_max_depth(); | ||
1054 | int pci_try_num; | ||
1055 | |||
1056 | |||
1057 | head.next = NULL; | ||
1058 | add_list.next = NULL; | ||
845 | 1059 | ||
1060 | pci_try_num = max_depth + 1; | ||
1061 | printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n", | ||
1062 | max_depth, pci_try_num); | ||
1063 | |||
1064 | again: | ||
846 | /* Depth first, calculate sizes and alignments of all | 1065 | /* Depth first, calculate sizes and alignments of all |
847 | subordinate buses. */ | 1066 | subordinate buses. */ |
848 | list_for_each_entry(bus, &pci_root_buses, node) { | 1067 | list_for_each_entry(bus, &pci_root_buses, node) |
849 | pci_bus_size_bridges(bus); | 1068 | __pci_bus_size_bridges(bus, &add_list); |
850 | } | 1069 | |
851 | /* Depth last, allocate resources and update the hardware. */ | 1070 | /* Depth last, allocate resources and update the hardware. */ |
852 | list_for_each_entry(bus, &pci_root_buses, node) { | 1071 | list_for_each_entry(bus, &pci_root_buses, node) |
853 | pci_bus_assign_resources(bus); | 1072 | __pci_bus_assign_resources(bus, &add_list, &head); |
854 | pci_enable_bridges(bus); | 1073 | BUG_ON(add_list.next); |
1074 | tried_times++; | ||
1075 | |||
1076 | /* any device complain? */ | ||
1077 | if (!head.next) | ||
1078 | goto enable_and_dump; | ||
1079 | |||
1080 | /* don't realloc if asked to do so */ | ||
1081 | if (!pci_realloc_enabled()) { | ||
1082 | free_list(resource_list_x, &head); | ||
1083 | goto enable_and_dump; | ||
1084 | } | ||
1085 | |||
1086 | failed_type = 0; | ||
1087 | for (list = head.next; list;) { | ||
1088 | failed_type |= list->flags; | ||
1089 | list = list->next; | ||
1090 | } | ||
1091 | /* | ||
1092 | * io port are tight, don't try extra | ||
1093 | * or if reach the limit, don't want to try more | ||
1094 | */ | ||
1095 | failed_type &= type_mask; | ||
1096 | if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) { | ||
1097 | free_list(resource_list_x, &head); | ||
1098 | goto enable_and_dump; | ||
855 | } | 1099 | } |
856 | 1100 | ||
1101 | printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n", | ||
1102 | tried_times + 1); | ||
1103 | |||
1104 | /* third times and later will not check if it is leaf */ | ||
1105 | if ((tried_times + 1) > 2) | ||
1106 | rel_type = whole_subtree; | ||
1107 | |||
1108 | /* | ||
1109 | * Try to release leaf bridge's resources that doesn't fit resource of | ||
1110 | * child device under that bridge | ||
1111 | */ | ||
1112 | for (list = head.next; list;) { | ||
1113 | bus = list->dev->bus; | ||
1114 | pci_bus_release_bridge_resources(bus, list->flags & type_mask, | ||
1115 | rel_type); | ||
1116 | list = list->next; | ||
1117 | } | ||
1118 | /* restore size and flags */ | ||
1119 | for (list = head.next; list;) { | ||
1120 | struct resource *res = list->res; | ||
1121 | |||
1122 | res->start = list->start; | ||
1123 | res->end = list->end; | ||
1124 | res->flags = list->flags; | ||
1125 | if (list->dev->subordinate) | ||
1126 | res->flags = 0; | ||
1127 | |||
1128 | list = list->next; | ||
1129 | } | ||
1130 | free_list(resource_list_x, &head); | ||
1131 | |||
1132 | goto again; | ||
1133 | |||
1134 | enable_and_dump: | ||
1135 | /* Depth last, update the hardware. */ | ||
1136 | list_for_each_entry(bus, &pci_root_buses, node) | ||
1137 | pci_enable_bridges(bus); | ||
1138 | |||
857 | /* dump the resource on buses */ | 1139 | /* dump the resource on buses */ |
858 | list_for_each_entry(bus, &pci_root_buses, node) { | 1140 | list_for_each_entry(bus, &pci_root_buses, node) |
859 | pci_bus_dump_resources(bus); | 1141 | pci_bus_dump_resources(bus); |
860 | } | ||
861 | } | 1142 | } |
862 | 1143 | ||
863 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) | 1144 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) |
@@ -882,7 +1163,7 @@ again: | |||
882 | 1163 | ||
883 | if (tried_times >= 2) { | 1164 | if (tried_times >= 2) { |
884 | /* still fail, don't need to try more */ | 1165 | /* still fail, don't need to try more */ |
885 | free_failed_list(&head); | 1166 | free_list(resource_list_x, &head); |
886 | goto enable_all; | 1167 | goto enable_all; |
887 | } | 1168 | } |
888 | 1169 | ||
@@ -913,7 +1194,7 @@ again: | |||
913 | 1194 | ||
914 | list = list->next; | 1195 | list = list->next; |
915 | } | 1196 | } |
916 | free_failed_list(&head); | 1197 | free_list(resource_list_x, &head); |
917 | 1198 | ||
918 | goto again; | 1199 | goto again; |
919 | 1200 | ||