PCI: introduce pci_assign_unassigned_bridge_resources
authorYinghai Lu <yinghai@kernel.org>
Fri, 22 Jan 2010 09:02:25 +0000 (01:02 -0800)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Tue, 23 Feb 2010 00:17:23 +0000 (16:17 -0800)
For use by pciehp.

pci_setup_bridge() will not check enabled for the slot bridge, otherwise
update res is not updated to bridge BAR.  That is, bridge is already
enabled for port service.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Reviewed-by: Alex Chiang <achiang@hp.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/pci/setup-bus.c
include/linux/pci.h

index f76f6e90f3b99eb9b7b2c63a804d4be1cfd2c51d..b19a56b8b17a8eff1afa50aa67ddab95d8f0250c 100644 (file)
@@ -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);
index 8b79403cc0724bdeee33b91dbe27643210b6c148..f0c056780a1fe823e555229f88c6d297e5e583f2 100644 (file)
@@ -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);