summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/setup-bus.c116
-rw-r--r--include/linux/pci.h1
2 files changed, 90 insertions, 27 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index f76f6e90f3b9..b19a56b8b17a 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -71,35 +71,34 @@ static void free_failed_list(struct resource_list_x *head)
head->next = NULL;
}
-static void pbus_assign_resources_sorted(const struct pci_bus *bus,
- struct resource_list_x *fail_head)
+static void __dev_sort_resources(struct pci_dev *dev,
+ struct resource_list *head)
{
- struct pci_dev *dev;
- struct resource *res;
- struct resource_list head, *list, *tmp;
- int idx;
+ u16 class = dev->class >> 8;
- head.next = NULL;
- list_for_each_entry(dev, &bus->devices, bus_list) {
- u16 class = dev->class >> 8;
+ /* Don't touch classless devices or host bridges or ioapics. */
+ if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST)
+ return;
- /* Don't touch classless devices or host bridges or ioapics. */
- if (class == PCI_CLASS_NOT_DEFINED ||
- class == PCI_CLASS_BRIDGE_HOST)
- continue;
+ /* Don't touch ioapic devices already enabled by firmware */
+ if (class == PCI_CLASS_SYSTEM_PIC) {
+ u16 command;
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
+ return;
+ }
- /* Don't touch ioapic devices already enabled by firmware */
- if (class == PCI_CLASS_SYSTEM_PIC) {
- u16 command;
- pci_read_config_word(dev, PCI_COMMAND, &command);
- if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
- continue;
- }
+ pdev_sort_resources(dev, head);
+}
- pdev_sort_resources(dev, &head);
- }
+static void __assign_resources_sorted(struct resource_list *head,
+ struct resource_list_x *fail_head)
+{
+ struct resource *res;
+ struct resource_list *list, *tmp;
+ int idx;
- for (list = head.next; list;) {
+ for (list = head->next; list;) {
res = list->res;
idx = res - &list->dev->resource[0];
if (pci_assign_resource(list->dev, idx)) {
@@ -115,6 +114,30 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus,
}
}
+static void pdev_assign_resources_sorted(struct pci_dev *dev,
+ struct resource_list_x *fail_head)
+{
+ struct resource_list head;
+
+ head.next = NULL;
+ __dev_sort_resources(dev, &head);
+ __assign_resources_sorted(&head, fail_head);
+
+}
+
+static void pbus_assign_resources_sorted(const struct pci_bus *bus,
+ struct resource_list_x *fail_head)
+{
+ struct pci_dev *dev;
+ struct resource_list head;
+
+ head.next = NULL;
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ __dev_sort_resources(dev, &head);
+
+ __assign_resources_sorted(&head, fail_head);
+}
+
void pci_setup_cardbus(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
@@ -273,9 +296,6 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type)
{
struct pci_dev *bridge = bus->self;
- if (pci_is_enabled(bridge))
- return;
-
dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
bus->secondary, bus->subordinate);
@@ -646,7 +666,8 @@ static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
- pci_setup_bridge(b);
+ if (!pci_is_enabled(dev))
+ pci_setup_bridge(b);
break;
case PCI_CLASS_BRIDGE_CARDBUS:
@@ -667,6 +688,34 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus)
}
EXPORT_SYMBOL(pci_bus_assign_resources);
+static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
+ struct resource_list_x *fail_head)
+{
+ struct pci_bus *b;
+
+ pdev_assign_resources_sorted((struct pci_dev *)bridge, fail_head);
+
+ b = bridge->subordinate;
+ if (!b)
+ return;
+
+ __pci_bus_assign_resources(b, fail_head);
+
+ switch (bridge->class >> 8) {
+ case PCI_CLASS_BRIDGE_PCI:
+ pci_setup_bridge(b);
+ break;
+
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ pci_setup_cardbus(b);
+ break;
+
+ default:
+ dev_info(&bridge->dev, "not setting up bridge for bus "
+ "%04x:%02x\n", pci_domain_nr(b), b->number);
+ break;
+ }
+}
static void pci_bridge_release_resources(struct pci_bus *bus,
unsigned long type)
{
@@ -911,3 +960,16 @@ enable_and_dump:
pci_bus_dump_resources(bus);
}
}
+
+void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
+{
+ struct pci_bus *parent = bridge->subordinate;
+ int retval;
+
+ pci_bus_size_bridges(parent);
+ __pci_bridge_assign_resources(bridge, NULL);
+ retval = pci_reenable_device(bridge);
+ pci_set_master(bridge);
+ pci_enable_bridges(parent);
+}
+EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 8b79403cc072..f0c056780a1f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -801,6 +801,7 @@ void pci_bus_assign_resources(const struct pci_bus *bus);
void pci_bus_size_bridges(struct pci_bus *bus);
int pci_claim_resource(struct pci_dev *, int);
void pci_assign_unassigned_resources(void);
+void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
void pdev_enable_device(struct pci_dev *);
void pdev_sort_resources(struct pci_dev *, struct resource_list *);
int pci_enable_resources(struct pci_dev *, int mask);