forked from luck/tmp_suning_uos_patched
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 <nfont@austin.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
parent
6098e2ee14
commit
e90a131846
|
@ -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_claim_one_bus(struct pci_bus *b);
|
||||||
|
|
||||||
|
extern void pcibios_allocate_bus_resources(struct pci_bus *bus);
|
||||||
|
|
||||||
extern void pcibios_resource_survey(void);
|
extern void pcibios_resource_survey(void);
|
||||||
|
|
||||||
extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
|
extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
|
||||||
|
|
|
@ -1239,69 +1239,66 @@ static int __init reparent_resources(struct resource *parent,
|
||||||
* as well.
|
* 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;
|
int i;
|
||||||
struct resource *res, *pr;
|
struct resource *res, *pr;
|
||||||
|
|
||||||
/* Depth-First Search on bus tree */
|
for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
|
||||||
list_for_each_entry(bus, bus_list, node) {
|
if ((res = bus->resource[i]) == NULL || !res->flags
|
||||||
for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
|
|| res->start > res->end)
|
||||||
if ((res = bus->resource[i]) == NULL || !res->flags
|
continue;
|
||||||
|| res->start > res->end)
|
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
|
||||||
|
*/
|
||||||
continue;
|
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
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
pcibios_allocate_bus_resources(&bus->children);
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
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)
|
void __init pcibios_resource_survey(void)
|
||||||
{
|
{
|
||||||
|
struct pci_bus *b;
|
||||||
|
|
||||||
/* Allocate and assign resources. If we re-assign everything, then
|
/* Allocate and assign resources. If we re-assign everything, then
|
||||||
* we skip the allocate phase
|
* 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)) {
|
if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) {
|
||||||
pcibios_allocate_resources(0);
|
pcibios_allocate_resources(0);
|
||||||
|
|
|
@ -189,6 +189,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
|
||||||
{
|
{
|
||||||
struct pci_controller *phb;
|
struct pci_controller *phb;
|
||||||
int primary;
|
int primary;
|
||||||
|
struct pci_bus *b;
|
||||||
|
|
||||||
primary = list_empty(&hose_list);
|
primary = list_empty(&hose_list);
|
||||||
phb = pcibios_alloc_controller(dn);
|
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);
|
eeh_add_device_tree_early(dn);
|
||||||
|
|
||||||
scan_phb(phb);
|
scan_phb(phb);
|
||||||
|
pcibios_allocate_bus_resources(phb->bus);
|
||||||
pcibios_fixup_new_pci_devices(phb->bus);
|
pcibios_fixup_new_pci_devices(phb->bus);
|
||||||
pci_bus_add_devices(phb->bus);
|
pci_bus_add_devices(phb->bus);
|
||||||
eeh_add_device_tree_late(phb->bus);
|
eeh_add_device_tree_late(phb->bus);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user