|
@@ -27,7 +27,52 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include "pci.h"
|
|
|
|
|
|
-static void pbus_assign_resources_sorted(const struct pci_bus *bus)
|
|
|
+struct resource_list_x {
|
|
|
+ struct resource_list_x *next;
|
|
|
+ struct resource *res;
|
|
|
+ struct pci_dev *dev;
|
|
|
+ resource_size_t start;
|
|
|
+ resource_size_t end;
|
|
|
+ unsigned long flags;
|
|
|
+};
|
|
|
+
|
|
|
+static void add_to_failed_list(struct resource_list_x *head,
|
|
|
+ struct pci_dev *dev, struct resource *res)
|
|
|
+{
|
|
|
+ struct resource_list_x *list = head;
|
|
|
+ struct resource_list_x *ln = list->next;
|
|
|
+ struct resource_list_x *tmp;
|
|
|
+
|
|
|
+ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
|
|
|
+ if (!tmp) {
|
|
|
+ pr_warning("add_to_failed_list: kmalloc() failed!\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ tmp->next = ln;
|
|
|
+ tmp->res = res;
|
|
|
+ tmp->dev = dev;
|
|
|
+ tmp->start = res->start;
|
|
|
+ tmp->end = res->end;
|
|
|
+ tmp->flags = res->flags;
|
|
|
+ list->next = tmp;
|
|
|
+}
|
|
|
+
|
|
|
+static void free_failed_list(struct resource_list_x *head)
|
|
|
+{
|
|
|
+ struct resource_list_x *list, *tmp;
|
|
|
+
|
|
|
+ for (list = head->next; list;) {
|
|
|
+ tmp = list;
|
|
|
+ list = list->next;
|
|
|
+ kfree(tmp);
|
|
|
+ }
|
|
|
+
|
|
|
+ head->next = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static void pbus_assign_resources_sorted(const struct pci_bus *bus,
|
|
|
+ struct resource_list_x *fail_head)
|
|
|
{
|
|
|
struct pci_dev *dev;
|
|
|
struct resource *res;
|
|
@@ -58,6 +103,8 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus)
|
|
|
res = list->res;
|
|
|
idx = res - &list->dev->resource[0];
|
|
|
if (pci_assign_resource(list->dev, idx)) {
|
|
|
+ if (fail_head && !pci_is_root_bus(list->dev->bus))
|
|
|
+ add_to_failed_list(fail_head, list->dev, res);
|
|
|
res->start = 0;
|
|
|
res->end = 0;
|
|
|
res->flags = 0;
|
|
@@ -572,19 +619,20 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
|
|
|
}
|
|
|
EXPORT_SYMBOL(pci_bus_size_bridges);
|
|
|
|
|
|
-void __ref pci_bus_assign_resources(const struct pci_bus *bus)
|
|
|
+static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
|
|
|
+ struct resource_list_x *fail_head)
|
|
|
{
|
|
|
struct pci_bus *b;
|
|
|
struct pci_dev *dev;
|
|
|
|
|
|
- pbus_assign_resources_sorted(bus);
|
|
|
+ pbus_assign_resources_sorted(bus, fail_head);
|
|
|
|
|
|
list_for_each_entry(dev, &bus->devices, bus_list) {
|
|
|
b = dev->subordinate;
|
|
|
if (!b)
|
|
|
continue;
|
|
|
|
|
|
- pci_bus_assign_resources(b);
|
|
|
+ __pci_bus_assign_resources(b, fail_head);
|
|
|
|
|
|
switch (dev->class >> 8) {
|
|
|
case PCI_CLASS_BRIDGE_PCI:
|
|
@@ -602,6 +650,11 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+void __ref pci_bus_assign_resources(const struct pci_bus *bus)
|
|
|
+{
|
|
|
+ __pci_bus_assign_resources(bus, NULL);
|
|
|
+}
|
|
|
EXPORT_SYMBOL(pci_bus_assign_resources);
|
|
|
|
|
|
static void pci_bridge_release_resources(struct pci_bus *bus,
|