From: Nathan Fontenot Date: Mon, 27 Oct 2008 19:48:17 +0000 (+0000) Subject: powerpc/pci: Properly allocate bus resources for hotplug PHBs X-Git-Tag: v2.6.28-rc3~22^2~9 X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=e90a13184600ec756875238ad130e2f205cd9a1b;p=linux-2.6-omap-h63xx.git powerpc/pci: Properly allocate bus resources for hotplug PHBs 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 Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h index 39d547fde95..57a2a494886 100644 --- a/arch/powerpc/include/asm/pci.h +++ b/arch/powerpc/include/asm/pci.h @@ -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); diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 1ec73938a00..f36936d9fda 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -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); diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 21a6d55418f..31481dc485d 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -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);