aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/setup-bus.c
diff options
context:
space:
mode:
authorRam Pai <linuxram@us.ibm.com>2011-02-14 20:43:20 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-03-04 13:46:47 -0500
commitc8adf9a3e873eddaaec11ac410a99ef6b9656938 (patch)
tree020eacc6e04b1f78268c2c3508d6ac88cae1806c /drivers/pci/setup-bus.c
parentfc075e1da1b96ef65c32e83648055606b8204b58 (diff)
PCI: pre-allocate additional resources to devices only after successful allocation of essential resources.
Linux tries to pre-allocate minimal resources to hotplug bridges. This works fine as long as there are enough resources to satisfy all other genuine resource requirements. However if enough resources are not available to satisfy any of these nice-to-have pre-allocations, the resource-allocator reports errors and returns failure. This patch distinguishes between must-have resource from nice-to-have resource. Any failure to allocate nice-to-have resources are ignored. This behavior can be particularly useful to trigger automatic reallocation when the OS discovers genuine allocation-conflicts or genuine unallocated-requests caused by buggy allocation behavior of the native BIOS/uEFI. https://bugzilla.kernel.org/show_bug.cgi?id=15960 captures the movitation behind the patch. This patch is verified to resolve the above bug. changelog v2: o fixed a bug where pci_assign_resource() was called on a resource of zero resource size. changelog v3: addressed Bjorn's comment o "Please don't indent and right-justify the changelog". o removed add_size from struct resource. The additional size is now tracked using a linked list. changelog v4: o moved freeing up of elements in head list from assign_requested_resources_sorted() to __assign_resources_sorted(). o removed a wrong reference to 'add_size' in pbus_size_mem(). o some code optimizations in adjust_resources_sorted() and assign_requested_resources_sorted() changelog v5: o moved freeing up of elements in head list from assign_requested_resources_sorted() to __assign_resources_sorted(). o removed a wrong reference to 'add_size' in pbus_size_mem(). o some code optimizations in adjust_resources_sorted() and assign_requested_resources_sorted() changelog v5: o factored out common code and made them into separate independent patches o added comments in kdoc format o added a BUG_ON in pci_assign_unassigned_resources() to catch for memory leak. Signed-off-by: Ram Pai <linuxram@us.ibm.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r--drivers/pci/setup-bus.c231
1 files changed, 184 insertions, 47 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index a94ecc161208..89d0a6a88df7 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -33,6 +33,7 @@ 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
@@ -46,8 +47,18 @@ struct resource_list_x {
46 (head)->next = NULL; \ 47 (head)->next = NULL; \
47} while (0) 48} while (0)
48 49
49static void add_to_failed_list(struct resource_list_x *head, 50/**
50 struct pci_dev *dev, struct resource *res) 51 * add_to_list() - add a new resource tracker to the list
52 * @head: Head of the list
53 * @dev: device corresponding to which the resource
54 * belongs
55 * @res: The resource to be tracked
56 * @add_size: additional size to be optionally added
57 * to the resource
58 */
59static void add_to_list(struct resource_list_x *head,
60 struct pci_dev *dev, struct resource *res,
61 resource_size_t add_size)
51{ 62{
52 struct resource_list_x *list = head; 63 struct resource_list_x *list = head;
53 struct resource_list_x *ln = list->next; 64 struct resource_list_x *ln = list->next;
@@ -55,7 +66,7 @@ static void add_to_failed_list(struct resource_list_x *head,
55 66
56 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); 67 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
57 if (!tmp) { 68 if (!tmp) {
58 pr_warning("add_to_failed_list: kmalloc() failed!\n"); 69 pr_warning("add_to_list: kmalloc() failed!\n");
59 return; 70 return;
60 } 71 }
61 72
@@ -65,9 +76,16 @@ static void add_to_failed_list(struct resource_list_x *head,
65 tmp->start = res->start; 76 tmp->start = res->start;
66 tmp->end = res->end; 77 tmp->end = res->end;
67 tmp->flags = res->flags; 78 tmp->flags = res->flags;
79 tmp->add_size = add_size;
68 list->next = tmp; 80 list->next = tmp;
69} 81}
70 82
83static void add_to_failed_list(struct resource_list_x *head,
84 struct pci_dev *dev, struct resource *res)
85{
86 add_to_list(head, dev, res, 0);
87}
88
71static void __dev_sort_resources(struct pci_dev *dev, 89static void __dev_sort_resources(struct pci_dev *dev,
72 struct resource_list *head) 90 struct resource_list *head)
73{ 91{
@@ -95,18 +113,81 @@ static inline void reset_resource(struct resource *res)
95 res->flags = 0; 113 res->flags = 0;
96} 114}
97 115
98static void __assign_resources_sorted(struct resource_list *head, 116/**
99 struct resource_list_x *fail_head) 117 * adjust_resources_sorted() - satisfy any additional resource requests
118 *
119 * @add_head : head of the list tracking requests requiring additional
120 * resources
121 * @head : head of the list tracking requests with allocated
122 * resources
123 *
124 * Walk through each element of the add_head and try to procure
125 * additional resources for the element, provided the element
126 * is in the head list.
127 */
128static void adjust_resources_sorted(struct resource_list_x *add_head,
129 struct resource_list *head)
100{ 130{
101 struct resource *res; 131 struct resource *res;
102 struct resource_list *list, *tmp; 132 struct resource_list_x *list, *tmp, *prev;
133 struct resource_list *hlist;
134 resource_size_t add_size;
103 int idx; 135 int idx;
104 136
105 for (list = head->next; list;) { 137 prev = add_head;
138 for (list = add_head->next; list;) {
106 res = list->res; 139 res = list->res;
140 /* skip resource that has been reset */
141 if (!res->flags)
142 goto out;
143
144 /* skip this resource if not found in head list */
145 for (hlist = head->next; hlist && hlist->res != res;
146 hlist = hlist->next);
147 if (!hlist) { /* just skip */
148 prev = list;
149 list = list->next;
150 continue;
151 }
152
107 idx = res - &list->dev->resource[0]; 153 idx = res - &list->dev->resource[0];
154 add_size=list->add_size;
155 if (!resource_size(res) && add_size) {
156 res->end = res->start + add_size - 1;
157 if(pci_assign_resource(list->dev, idx))
158 reset_resource(res);
159 } else if (add_size) {
160 adjust_resource(res, res->start,
161 resource_size(res) + add_size);
162 }
163out:
164 tmp = list;
165 prev->next = list = list->next;
166 kfree(tmp);
167 }
168}
169
170/**
171 * assign_requested_resources_sorted() - satisfy resource requests
172 *
173 * @head : head of the list tracking requests for resources
174 * @failed_list : head of the list tracking requests that could
175 * not be allocated
176 *
177 * Satisfy resource requests of each element in the list. Add
178 * requests that could not satisfied to the failed_list.
179 */
180static void assign_requested_resources_sorted(struct resource_list *head,
181 struct resource_list_x *fail_head)
182{
183 struct resource *res;
184 struct resource_list *list;
185 int idx;
108 186
109 if (pci_assign_resource(list->dev, idx)) { 187 for (list = head->next; list; list = list->next) {
188 res = list->res;
189 idx = res - &list->dev->resource[0];
190 if (resource_size(res) && pci_assign_resource(list->dev, idx)) {
110 if (fail_head && !pci_is_root_bus(list->dev->bus)) { 191 if (fail_head && !pci_is_root_bus(list->dev->bus)) {
111 /* 192 /*
112 * if the failed res is for ROM BAR, and it will 193 * if the failed res is for ROM BAR, and it will
@@ -118,12 +199,23 @@ static void __assign_resources_sorted(struct resource_list *head,
118 } 199 }
119 reset_resource(res); 200 reset_resource(res);
120 } 201 }
121 tmp = list;
122 list = list->next;
123 kfree(tmp);
124 } 202 }
125} 203}
126 204
205static void __assign_resources_sorted(struct resource_list *head,
206 struct resource_list_x *add_head,
207 struct resource_list_x *fail_head)
208{
209 /* Satisfy the must-have resource requests */
210 assign_requested_resources_sorted(head, fail_head);
211
212 /* Try to satisfy any additional nice-to-have resource
213 requests */
214 if (add_head)
215 adjust_resources_sorted(add_head, head);
216 free_list(resource_list, head);
217}
218
127static void pdev_assign_resources_sorted(struct pci_dev *dev, 219static void pdev_assign_resources_sorted(struct pci_dev *dev,
128 struct resource_list_x *fail_head) 220 struct resource_list_x *fail_head)
129{ 221{
@@ -131,11 +223,12 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev,
131 223
132 head.next = NULL; 224 head.next = NULL;
133 __dev_sort_resources(dev, &head); 225 __dev_sort_resources(dev, &head);
134 __assign_resources_sorted(&head, fail_head); 226 __assign_resources_sorted(&head, NULL, fail_head);
135 227
136} 228}
137 229
138static void pbus_assign_resources_sorted(const struct pci_bus *bus, 230static void pbus_assign_resources_sorted(const struct pci_bus *bus,
231 struct resource_list_x *add_head,
139 struct resource_list_x *fail_head) 232 struct resource_list_x *fail_head)
140{ 233{
141 struct pci_dev *dev; 234 struct pci_dev *dev;
@@ -145,7 +238,7 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus,
145 list_for_each_entry(dev, &bus->devices, bus_list) 238 list_for_each_entry(dev, &bus->devices, bus_list)
146 __dev_sort_resources(dev, &head); 239 __dev_sort_resources(dev, &head);
147 240
148 __assign_resources_sorted(&head, fail_head); 241 __assign_resources_sorted(&head, add_head, fail_head);
149} 242}
150 243
151void pci_setup_cardbus(struct pci_bus *bus) 244void pci_setup_cardbus(struct pci_bus *bus)
@@ -443,15 +536,25 @@ static resource_size_t calculate_memsize(resource_size_t size,
443 return size; 536 return size;
444} 537}
445 538
446/* Sizing the IO windows of the PCI-PCI bridge is trivial, 539/**
447 since these windows have 4K granularity and the IO ranges 540 * pbus_size_io() - size the io window of a given bus
448 of non-bridge PCI devices are limited to 256 bytes. 541 *
449 We must be careful with the ISA aliasing though. */ 542 * @bus : the bus
450static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) 543 * @min_size : the minimum io window that must to be allocated
544 * @add_size : additional optional io window
545 * @add_head : track the additional io window on this list
546 *
547 * Sizing the IO windows of the PCI-PCI bridge is trivial,
548 * since these windows have 4K granularity and the IO ranges
549 * of non-bridge PCI devices are limited to 256 bytes.
550 * We must be careful with the ISA aliasing though.
551 */
552static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
553 resource_size_t add_size, struct resource_list_x *add_head)
451{ 554{
452 struct pci_dev *dev; 555 struct pci_dev *dev;
453 struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); 556 struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
454 unsigned long size = 0, size1 = 0; 557 unsigned long size = 0, size0 = 0, size1 = 0;
455 558
456 if (!b_res) 559 if (!b_res)
457 return; 560 return;
@@ -474,9 +577,12 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
474 size1 += r_size; 577 size1 += r_size;
475 } 578 }
476 } 579 }
477 size = calculate_iosize(size, min_size, size1, 580 size0 = calculate_iosize(size, min_size, size1,
581 resource_size(b_res), 4096);
582 size1 = !add_size? size0:
583 calculate_iosize(size, min_size+add_size, size1,
478 resource_size(b_res), 4096); 584 resource_size(b_res), 4096);
479 if (!size) { 585 if (!size0 && !size1) {
480 if (b_res->start || b_res->end) 586 if (b_res->start || b_res->end)
481 dev_info(&bus->self->dev, "disabling bridge window " 587 dev_info(&bus->self->dev, "disabling bridge window "
482 "%pR to [bus %02x-%02x] (unused)\n", b_res, 588 "%pR to [bus %02x-%02x] (unused)\n", b_res,
@@ -486,17 +592,30 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
486 } 592 }
487 /* Alignment of the IO window is always 4K */ 593 /* Alignment of the IO window is always 4K */
488 b_res->start = 4096; 594 b_res->start = 4096;
489 b_res->end = b_res->start + size - 1; 595 b_res->end = b_res->start + size0 - 1;
490 b_res->flags |= IORESOURCE_STARTALIGN; 596 b_res->flags |= IORESOURCE_STARTALIGN;
597 if (size1 > size0 && add_head)
598 add_to_list(add_head, bus->self, b_res, size1-size0);
491} 599}
492 600
493/* Calculate the size of the bus and minimal alignment which 601/**
494 guarantees that all child resources fit in this size. */ 602 * pbus_size_mem() - size the memory window of a given bus
603 *
604 * @bus : the bus
605 * @min_size : the minimum memory window that must to be allocated
606 * @add_size : additional optional memory window
607 * @add_head : track the additional memory window on this list
608 *
609 * Calculate the size of the bus and minimal alignment which
610 * guarantees that all child resources fit in this size.
611 */
495static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, 612static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
496 unsigned long type, resource_size_t min_size) 613 unsigned long type, resource_size_t min_size,
614 resource_size_t add_size,
615 struct resource_list_x *add_head)
497{ 616{
498 struct pci_dev *dev; 617 struct pci_dev *dev;
499 resource_size_t min_align, align, size; 618 resource_size_t min_align, align, size, size0, size1;
500 resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ 619 resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
501 int order, max_order; 620 int order, max_order;
502 struct resource *b_res = find_free_bus_resource(bus, type); 621 struct resource *b_res = find_free_bus_resource(bus, type);
@@ -557,8 +676,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
557 min_align = align1 >> 1; 676 min_align = align1 >> 1;
558 align += aligns[order]; 677 align += aligns[order];
559 } 678 }
560 size = calculate_memsize(size, min_size, 0, resource_size(b_res), align); 679 size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), align);
561 if (!size) { 680 size1 = !add_size ? size :
681 calculate_memsize(size, min_size+add_size, 0,
682 resource_size(b_res), align);
683 if (!size0 && !size1) {
562 if (b_res->start || b_res->end) 684 if (b_res->start || b_res->end)
563 dev_info(&bus->self->dev, "disabling bridge window " 685 dev_info(&bus->self->dev, "disabling bridge window "
564 "%pR to [bus %02x-%02x] (unused)\n", b_res, 686 "%pR to [bus %02x-%02x] (unused)\n", b_res,
@@ -567,9 +689,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
567 return 1; 689 return 1;
568 } 690 }
569 b_res->start = min_align; 691 b_res->start = min_align;
570 b_res->end = size + min_align - 1; 692 b_res->end = size0 + min_align - 1;
571 b_res->flags |= IORESOURCE_STARTALIGN; 693 b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
572 b_res->flags |= mem64_mask; 694 if (size1 > size0 && add_head)
695 add_to_list(add_head, bus->self, b_res, size1-size0);
573 return 1; 696 return 1;
574} 697}
575 698
@@ -622,11 +745,12 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)
622 } 745 }
623} 746}
624 747
625void __ref pci_bus_size_bridges(struct pci_bus *bus) 748void __ref __pci_bus_size_bridges(struct pci_bus *bus,
749 struct resource_list_x *add_head)
626{ 750{
627 struct pci_dev *dev; 751 struct pci_dev *dev;
628 unsigned long mask, prefmask; 752 unsigned long mask, prefmask;
629 resource_size_t min_mem_size = 0, min_io_size = 0; 753 resource_size_t additional_mem_size = 0, additional_io_size = 0;
630 754
631 list_for_each_entry(dev, &bus->devices, bus_list) { 755 list_for_each_entry(dev, &bus->devices, bus_list) {
632 struct pci_bus *b = dev->subordinate; 756 struct pci_bus *b = dev->subordinate;
@@ -640,7 +764,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
640 764
641 case PCI_CLASS_BRIDGE_PCI: 765 case PCI_CLASS_BRIDGE_PCI:
642 default: 766 default:
643 pci_bus_size_bridges(b); 767 __pci_bus_size_bridges(b, add_head);
644 break; 768 break;
645 } 769 }
646 } 770 }
@@ -657,11 +781,14 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
657 case PCI_CLASS_BRIDGE_PCI: 781 case PCI_CLASS_BRIDGE_PCI:
658 pci_bridge_check_ranges(bus); 782 pci_bridge_check_ranges(bus);
659 if (bus->self->is_hotplug_bridge) { 783 if (bus->self->is_hotplug_bridge) {
660 min_io_size = pci_hotplug_io_size; 784 additional_io_size = pci_hotplug_io_size;
661 min_mem_size = pci_hotplug_mem_size; 785 additional_mem_size = pci_hotplug_mem_size;
662 } 786 }
787 /*
788 * Follow thru
789 */
663 default: 790 default:
664 pbus_size_io(bus, min_io_size); 791 pbus_size_io(bus, 0, additional_io_size, add_head);
665 /* If the bridge supports prefetchable range, size it 792 /* If the bridge supports prefetchable range, size it
666 separately. If it doesn't, or its prefetchable window 793 separately. If it doesn't, or its prefetchable window
667 has already been allocated by arch code, try 794 has already been allocated by arch code, try
@@ -669,30 +796,36 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
669 resources. */ 796 resources. */
670 mask = IORESOURCE_MEM; 797 mask = IORESOURCE_MEM;
671 prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; 798 prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
672 if (pbus_size_mem(bus, prefmask, prefmask, min_mem_size)) 799 if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, add_head))
673 mask = prefmask; /* Success, size non-prefetch only. */ 800 mask = prefmask; /* Success, size non-prefetch only. */
674 else 801 else
675 min_mem_size += min_mem_size; 802 additional_mem_size += additional_mem_size;
676 pbus_size_mem(bus, mask, IORESOURCE_MEM, min_mem_size); 803 pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, add_head);
677 break; 804 break;
678 } 805 }
679} 806}
807
808void __ref pci_bus_size_bridges(struct pci_bus *bus)
809{
810 __pci_bus_size_bridges(bus, NULL);
811}
680EXPORT_SYMBOL(pci_bus_size_bridges); 812EXPORT_SYMBOL(pci_bus_size_bridges);
681 813
682static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, 814static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
815 struct resource_list_x *add_head,
683 struct resource_list_x *fail_head) 816 struct resource_list_x *fail_head)
684{ 817{
685 struct pci_bus *b; 818 struct pci_bus *b;
686 struct pci_dev *dev; 819 struct pci_dev *dev;
687 820
688 pbus_assign_resources_sorted(bus, fail_head); 821 pbus_assign_resources_sorted(bus, add_head, fail_head);
689 822
690 list_for_each_entry(dev, &bus->devices, bus_list) { 823 list_for_each_entry(dev, &bus->devices, bus_list) {
691 b = dev->subordinate; 824 b = dev->subordinate;
692 if (!b) 825 if (!b)
693 continue; 826 continue;
694 827
695 __pci_bus_assign_resources(b, fail_head); 828 __pci_bus_assign_resources(b, add_head, fail_head);
696 829
697 switch (dev->class >> 8) { 830 switch (dev->class >> 8) {
698 case PCI_CLASS_BRIDGE_PCI: 831 case PCI_CLASS_BRIDGE_PCI:
@@ -714,7 +847,7 @@ static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
714 847
715void __ref pci_bus_assign_resources(const struct pci_bus *bus) 848void __ref pci_bus_assign_resources(const struct pci_bus *bus)
716{ 849{
717 __pci_bus_assign_resources(bus, NULL); 850 __pci_bus_assign_resources(bus, NULL, NULL);
718} 851}
719EXPORT_SYMBOL(pci_bus_assign_resources); 852EXPORT_SYMBOL(pci_bus_assign_resources);
720 853
@@ -729,7 +862,7 @@ static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
729 if (!b) 862 if (!b)
730 return; 863 return;
731 864
732 __pci_bus_assign_resources(b, fail_head); 865 __pci_bus_assign_resources(b, NULL, fail_head);
733 866
734 switch (bridge->class >> 8) { 867 switch (bridge->class >> 8) {
735 case PCI_CLASS_BRIDGE_PCI: 868 case PCI_CLASS_BRIDGE_PCI:
@@ -862,17 +995,21 @@ void __init
862pci_assign_unassigned_resources(void) 995pci_assign_unassigned_resources(void)
863{ 996{
864 struct pci_bus *bus; 997 struct pci_bus *bus;
865 998 struct resource_list_x add_list; /* list of resources that
999 want additional resources */
1000 add_list.next = NULL;
866 /* Depth first, calculate sizes and alignments of all 1001 /* Depth first, calculate sizes and alignments of all
867 subordinate buses. */ 1002 subordinate buses. */
868 list_for_each_entry(bus, &pci_root_buses, node) { 1003 list_for_each_entry(bus, &pci_root_buses, node) {
869 pci_bus_size_bridges(bus); 1004 __pci_bus_size_bridges(bus, &add_list);
870 } 1005 }
1006
871 /* Depth last, allocate resources and update the hardware. */ 1007 /* Depth last, allocate resources and update the hardware. */
872 list_for_each_entry(bus, &pci_root_buses, node) { 1008 list_for_each_entry(bus, &pci_root_buses, node) {
873 pci_bus_assign_resources(bus); 1009 __pci_bus_assign_resources(bus, &add_list, NULL);
874 pci_enable_bridges(bus); 1010 pci_enable_bridges(bus);
875 } 1011 }
1012 BUG_ON(add_list.next);
876 1013
877 /* dump the resource on buses */ 1014 /* dump the resource on buses */
878 list_for_each_entry(bus, &pci_root_buses, node) { 1015 list_for_each_entry(bus, &pci_root_buses, node) {