diff options
-rw-r--r-- | drivers/pci/setup-bus.c | 61 |
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 | ||
30 | static void pbus_assign_resources_sorted(const struct pci_bus *bus) | 30 | struct 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 | |||
39 | static 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 | |||
61 | static 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 | |||
74 | static 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 | } |
573 | EXPORT_SYMBOL(pci_bus_size_bridges); | 620 | EXPORT_SYMBOL(pci_bus_size_bridges); |
574 | 621 | ||
575 | void __ref pci_bus_assign_resources(const struct pci_bus *bus) | 622 | static 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 | |||
654 | void __ref pci_bus_assign_resources(const struct pci_bus *bus) | ||
655 | { | ||
656 | __pci_bus_assign_resources(bus, NULL); | ||
657 | } | ||
605 | EXPORT_SYMBOL(pci_bus_assign_resources); | 658 | EXPORT_SYMBOL(pci_bus_assign_resources); |
606 | 659 | ||
607 | static void pci_bridge_release_resources(struct pci_bus *bus, | 660 | static void pci_bridge_release_resources(struct pci_bus *bus, |