powerpc/pci: Properly allocate bus resources for hotplug PHBs
authorNathan Fontenot <nfont@austin.ibm.com>
Mon, 27 Oct 2008 19:48:17 +0000 (19:48 +0000)
committerPaul Mackerras <paulus@samba.org>
Fri, 31 Oct 2008 05:12:03 +0000 (16:12 +1100)
Resources for PHB's that are dynamically added to a system are not
properly allocated in the resource tree.

Not having these resources allocated causes an oops when removing
the PHB when we try to release them.

The diff appears a bit messy, this is mainly due to moving everything
one tab to the left in the pcibios_allocate_bus_resources routine.
The functionality change in this routine is only that the
list_for_each_entry() loop is pulled out and moved to the necessary
calling routine.

Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/include/asm/pci.h
arch/powerpc/kernel/pci-common.c
arch/powerpc/platforms/pseries/pci_dlpar.c

index 39d547f..57a2a49 100644 (file)
@@ -208,6 +208,8 @@ extern void pcibios_setup_new_device(struct pci_dev *dev);
 
 extern void pcibios_claim_one_bus(struct pci_bus *b);
 
+extern void pcibios_allocate_bus_resources(struct pci_bus *bus);
+
 extern void pcibios_resource_survey(void);
 
 extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
index 1ec7393..f36936d 100644 (file)
@@ -1239,69 +1239,66 @@ static int __init reparent_resources(struct resource *parent,
  *         as well.
  */
 
-static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+void pcibios_allocate_bus_resources(struct pci_bus *bus)
 {
-       struct pci_bus *bus;
+       struct pci_bus *b;
        int i;
        struct resource *res, *pr;
 
-       /* Depth-First Search on bus tree */
-       list_for_each_entry(bus, bus_list, node) {
-               for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
-                       if ((res = bus->resource[i]) == NULL || !res->flags
-                           || res->start > res->end)
-                               continue;
-                       if (bus->parent == NULL)
-                               pr = (res->flags & IORESOURCE_IO) ?
-                                       &ioport_resource : &iomem_resource;
-                       else {
-                               /* Don't bother with non-root busses when
-                                * re-assigning all resources. We clear the
-                                * resource flags as if they were colliding
-                                * and as such ensure proper re-allocation
-                                * later.
+       for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
+               if ((res = bus->resource[i]) == NULL || !res->flags
+                   || res->start > res->end)
+                       continue;
+               if (bus->parent == NULL)
+                       pr = (res->flags & IORESOURCE_IO) ?
+                               &ioport_resource : &iomem_resource;
+               else {
+                       /* Don't bother with non-root busses when
+                        * re-assigning all resources. We clear the
+                        * resource flags as if they were colliding
+                        * and as such ensure proper re-allocation
+                        * later.
+                        */
+                       if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)
+                               goto clear_resource;
+                       pr = pci_find_parent_resource(bus->self, res);
+                       if (pr == res) {
+                               /* this happens when the generic PCI
+                                * code (wrongly) decides that this
+                                * bridge is transparent  -- paulus
                                 */
-                               if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)
-                                       goto clear_resource;
-                               pr = pci_find_parent_resource(bus->self, res);
-                               if (pr == res) {
-                                       /* this happens when the generic PCI
-                                        * code (wrongly) decides that this
-                                        * bridge is transparent  -- paulus
-                                        */
-                                       continue;
-                               }
+                               continue;
                        }
+               }
 
-                       DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "
-                           "[0x%x], parent %p (%s)\n",
-                           bus->self ? pci_name(bus->self) : "PHB",
-                           bus->number, i,
-                           (unsigned long long)res->start,
-                           (unsigned long long)res->end,
-                           (unsigned int)res->flags,
-                           pr, (pr && pr->name) ? pr->name : "nil");
-
-                       if (pr && !(pr->flags & IORESOURCE_UNSET)) {
-                               if (request_resource(pr, res) == 0)
-                                       continue;
-                               /*
-                                * Must be a conflict with an existing entry.
-                                * Move that entry (or entries) under the
-                                * bridge resource and try again.
-                                */
-                               if (reparent_resources(pr, res) == 0)
-                                       continue;
-                       }
-                       printk(KERN_WARNING
-                              "PCI: Cannot allocate resource region "
-                              "%d of PCI bridge %d, will remap\n",
-                              i, bus->number);
-clear_resource:
-                       res->flags = 0;
+               DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "
+                   "[0x%x], parent %p (%s)\n",
+                   bus->self ? pci_name(bus->self) : "PHB",
+                   bus->number, i,
+                   (unsigned long long)res->start,
+                   (unsigned long long)res->end,
+                   (unsigned int)res->flags,
+                   pr, (pr && pr->name) ? pr->name : "nil");
+
+               if (pr && !(pr->flags & IORESOURCE_UNSET)) {
+                       if (request_resource(pr, res) == 0)
+                               continue;
+                       /*
+                        * Must be a conflict with an existing entry.
+                        * Move that entry (or entries) under the
+                        * bridge resource and try again.
+                        */
+                       if (reparent_resources(pr, res) == 0)
+                               continue;
                }
-               pcibios_allocate_bus_resources(&bus->children);
+               printk(KERN_WARNING "PCI: Cannot allocate resource region "
+                      "%d of PCI bridge %d, will remap\n", i, bus->number);
+clear_resource:
+               res->flags = 0;
        }
+
+       list_for_each_entry(b, &bus->children, node)
+               pcibios_allocate_bus_resources(b);
 }
 
 static inline void __devinit alloc_resource(struct pci_dev *dev, int idx)
@@ -1372,10 +1369,13 @@ static void __init pcibios_allocate_resources(int pass)
 
 void __init pcibios_resource_survey(void)
 {
+       struct pci_bus *b;
+
        /* Allocate and assign resources. If we re-assign everything, then
         * we skip the allocate phase
         */
-       pcibios_allocate_bus_resources(&pci_root_buses);
+       list_for_each_entry(b, &pci_root_buses, node)
+               pcibios_allocate_bus_resources(b);
 
        if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) {
                pcibios_allocate_resources(0);
index 21a6d55..31481dc 100644 (file)
@@ -189,6 +189,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
 {
        struct pci_controller *phb;
        int primary;
+       struct pci_bus *b;
 
        primary = list_empty(&hose_list);
        phb = pcibios_alloc_controller(dn);
@@ -203,6 +204,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
                eeh_add_device_tree_early(dn);
 
        scan_phb(phb);
+       pcibios_allocate_bus_resources(phb->bus);
        pcibios_fixup_new_pci_devices(phb->bus);
        pci_bus_add_devices(phb->bus);
        eeh_add_device_tree_late(phb->bus);