aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/setup-bus.c61
1 files changed, 57 insertions, 4 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 7371a5479a99..7e87ea8f3200 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -27,7 +27,52 @@
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include "pci.h" 28#include "pci.h"
29 29
30static void pbus_assign_resources_sorted(const struct pci_bus *bus) 30struct resource_list_x {
31 struct resource_list_x *next;
32 struct resource *res;
33 struct pci_dev *dev;
34 resource_size_t start;
35 resource_size_t end;
36 unsigned long flags;
37};
38
39static void add_to_failed_list(struct resource_list_x *head,
40 struct pci_dev *dev, struct resource *res)
41{
42 struct resource_list_x *list = head;
43 struct resource_list_x *ln = list->next;
44 struct resource_list_x *tmp;
45
46 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
47 if (!tmp) {
48 pr_warning("add_to_failed_list: kmalloc() failed!\n");
49 return;
50 }
51
52 tmp->next = ln;
53 tmp->res = res;
54 tmp->dev = dev;
55 tmp->start = res->start;
56 tmp->end = res->end;
57 tmp->flags = res->flags;
58 list->next = tmp;
59}
60
61static void free_failed_list(struct resource_list_x *head)
62{
63 struct resource_list_x *list, *tmp;
64
65 for (list = head->next; list;) {
66 tmp = list;
67 list = list->next;
68 kfree(tmp);
69 }
70
71 head->next = NULL;
72}
73
74static void pbus_assign_resources_sorted(const struct pci_bus *bus,
75 struct resource_list_x *fail_head)
31{ 76{
32 struct pci_dev *dev; 77 struct pci_dev *dev;
33 struct resource *res; 78 struct resource *res;
@@ -58,6 +103,8 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus)
58 res = list->res; 103 res = list->res;
59 idx = res - &list->dev->resource[0]; 104 idx = res - &list->dev->resource[0];
60 if (pci_assign_resource(list->dev, idx)) { 105 if (pci_assign_resource(list->dev, idx)) {
106 if (fail_head && !pci_is_root_bus(list->dev->bus))
107 add_to_failed_list(fail_head, list->dev, res);
61 res->start = 0; 108 res->start = 0;
62 res->end = 0; 109 res->end = 0;
63 res->flags = 0; 110 res->flags = 0;
@@ -572,19 +619,20 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
572} 619}
573EXPORT_SYMBOL(pci_bus_size_bridges); 620EXPORT_SYMBOL(pci_bus_size_bridges);
574 621
575void __ref pci_bus_assign_resources(const struct pci_bus *bus) 622static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
623 struct resource_list_x *fail_head)
576{ 624{
577 struct pci_bus *b; 625 struct pci_bus *b;
578 struct pci_dev *dev; 626 struct pci_dev *dev;
579 627
580 pbus_assign_resources_sorted(bus); 628 pbus_assign_resources_sorted(bus, fail_head);
581 629
582 list_for_each_entry(dev, &bus->devices, bus_list) { 630 list_for_each_entry(dev, &bus->devices, bus_list) {
583 b = dev->subordinate; 631 b = dev->subordinate;
584 if (!b) 632 if (!b)
585 continue; 633 continue;
586 634
587 pci_bus_assign_resources(b); 635 __pci_bus_assign_resources(b, fail_head);
588 636
589 switch (dev->class >> 8) { 637 switch (dev->class >> 8) {
590 case PCI_CLASS_BRIDGE_PCI: 638 case PCI_CLASS_BRIDGE_PCI:
@@ -602,6 +650,11 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus)
602 } 650 }
603 } 651 }
604} 652}
653
654void __ref pci_bus_assign_resources(const struct pci_bus *bus)
655{
656 __pci_bus_assign_resources(bus, NULL);
657}
605EXPORT_SYMBOL(pci_bus_assign_resources); 658EXPORT_SYMBOL(pci_bus_assign_resources);
606 659
607static void pci_bridge_release_resources(struct pci_bus *bus, 660static void pci_bridge_release_resources(struct pci_bus *bus,