diff options
author | Nathan Fontenot <nfont@austin.ibm.com> | 2008-10-27 15:48:17 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-10-31 01:12:03 -0400 |
commit | e90a13184600ec756875238ad130e2f205cd9a1b (patch) | |
tree | 2a82267eebaef48a8ce2001d2a1e6ec6d87ce1a3 /arch | |
parent | 6098e2ee14849e0819ffa887ebf470dcfad4a2be (diff) |
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/pci.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci-common.c | 110 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci_dlpar.c | 2 |
3 files changed, 59 insertions, 55 deletions
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h index 39d547fde956..57a2a494886b 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); | |||
208 | 208 | ||
209 | extern void pcibios_claim_one_bus(struct pci_bus *b); | 209 | extern void pcibios_claim_one_bus(struct pci_bus *b); |
210 | 210 | ||
211 | extern void pcibios_allocate_bus_resources(struct pci_bus *bus); | ||
212 | |||
211 | extern void pcibios_resource_survey(void); | 213 | extern void pcibios_resource_survey(void); |
212 | 214 | ||
213 | extern struct pci_controller *init_phb_dynamic(struct device_node *dn); | 215 | 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 1ec73938a00f..f36936d9fda3 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, | |||
1239 | * as well. | 1239 | * as well. |
1240 | */ | 1240 | */ |
1241 | 1241 | ||
1242 | static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) | 1242 | void pcibios_allocate_bus_resources(struct pci_bus *bus) |
1243 | { | 1243 | { |
1244 | struct pci_bus *bus; | 1244 | struct pci_bus *b; |
1245 | int i; | 1245 | int i; |
1246 | struct resource *res, *pr; | 1246 | struct resource *res, *pr; |
1247 | 1247 | ||
1248 | /* Depth-First Search on bus tree */ | 1248 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { |
1249 | list_for_each_entry(bus, bus_list, node) { | 1249 | if ((res = bus->resource[i]) == NULL || !res->flags |
1250 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { | 1250 | || res->start > res->end) |
1251 | if ((res = bus->resource[i]) == NULL || !res->flags | 1251 | continue; |
1252 | || res->start > res->end) | 1252 | if (bus->parent == NULL) |
1253 | continue; | 1253 | pr = (res->flags & IORESOURCE_IO) ? |
1254 | if (bus->parent == NULL) | 1254 | &ioport_resource : &iomem_resource; |
1255 | pr = (res->flags & IORESOURCE_IO) ? | 1255 | else { |
1256 | &ioport_resource : &iomem_resource; | 1256 | /* Don't bother with non-root busses when |
1257 | else { | 1257 | * re-assigning all resources. We clear the |
1258 | /* Don't bother with non-root busses when | 1258 | * resource flags as if they were colliding |
1259 | * re-assigning all resources. We clear the | 1259 | * and as such ensure proper re-allocation |
1260 | * resource flags as if they were colliding | 1260 | * later. |
1261 | * and as such ensure proper re-allocation | 1261 | */ |
1262 | * later. | 1262 | if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC) |
1263 | goto clear_resource; | ||
1264 | pr = pci_find_parent_resource(bus->self, res); | ||
1265 | if (pr == res) { | ||
1266 | /* this happens when the generic PCI | ||
1267 | * code (wrongly) decides that this | ||
1268 | * bridge is transparent -- paulus | ||
1263 | */ | 1269 | */ |
1264 | if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC) | 1270 | continue; |
1265 | goto clear_resource; | ||
1266 | pr = pci_find_parent_resource(bus->self, res); | ||
1267 | if (pr == res) { | ||
1268 | /* this happens when the generic PCI | ||
1269 | * code (wrongly) decides that this | ||
1270 | * bridge is transparent -- paulus | ||
1271 | */ | ||
1272 | continue; | ||
1273 | } | ||
1274 | } | 1271 | } |
1272 | } | ||
1275 | 1273 | ||
1276 | DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx " | 1274 | DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx " |
1277 | "[0x%x], parent %p (%s)\n", | 1275 | "[0x%x], parent %p (%s)\n", |
1278 | bus->self ? pci_name(bus->self) : "PHB", | 1276 | bus->self ? pci_name(bus->self) : "PHB", |
1279 | bus->number, i, | 1277 | bus->number, i, |
1280 | (unsigned long long)res->start, | 1278 | (unsigned long long)res->start, |
1281 | (unsigned long long)res->end, | 1279 | (unsigned long long)res->end, |
1282 | (unsigned int)res->flags, | 1280 | (unsigned int)res->flags, |
1283 | pr, (pr && pr->name) ? pr->name : "nil"); | 1281 | pr, (pr && pr->name) ? pr->name : "nil"); |
1284 | 1282 | ||
1285 | if (pr && !(pr->flags & IORESOURCE_UNSET)) { | 1283 | if (pr && !(pr->flags & IORESOURCE_UNSET)) { |
1286 | if (request_resource(pr, res) == 0) | 1284 | if (request_resource(pr, res) == 0) |
1287 | continue; | 1285 | continue; |
1288 | /* | 1286 | /* |
1289 | * Must be a conflict with an existing entry. | 1287 | * Must be a conflict with an existing entry. |
1290 | * Move that entry (or entries) under the | 1288 | * Move that entry (or entries) under the |
1291 | * bridge resource and try again. | 1289 | * bridge resource and try again. |
1292 | */ | 1290 | */ |
1293 | if (reparent_resources(pr, res) == 0) | 1291 | if (reparent_resources(pr, res) == 0) |
1294 | continue; | 1292 | continue; |
1295 | } | ||
1296 | printk(KERN_WARNING | ||
1297 | "PCI: Cannot allocate resource region " | ||
1298 | "%d of PCI bridge %d, will remap\n", | ||
1299 | i, bus->number); | ||
1300 | clear_resource: | ||
1301 | res->flags = 0; | ||
1302 | } | 1293 | } |
1303 | pcibios_allocate_bus_resources(&bus->children); | 1294 | printk(KERN_WARNING "PCI: Cannot allocate resource region " |
1295 | "%d of PCI bridge %d, will remap\n", i, bus->number); | ||
1296 | clear_resource: | ||
1297 | res->flags = 0; | ||
1304 | } | 1298 | } |
1299 | |||
1300 | list_for_each_entry(b, &bus->children, node) | ||
1301 | pcibios_allocate_bus_resources(b); | ||
1305 | } | 1302 | } |
1306 | 1303 | ||
1307 | static inline void __devinit alloc_resource(struct pci_dev *dev, int idx) | 1304 | static inline void __devinit alloc_resource(struct pci_dev *dev, int idx) |
@@ -1372,10 +1369,13 @@ static void __init pcibios_allocate_resources(int pass) | |||
1372 | 1369 | ||
1373 | void __init pcibios_resource_survey(void) | 1370 | void __init pcibios_resource_survey(void) |
1374 | { | 1371 | { |
1372 | struct pci_bus *b; | ||
1373 | |||
1375 | /* Allocate and assign resources. If we re-assign everything, then | 1374 | /* Allocate and assign resources. If we re-assign everything, then |
1376 | * we skip the allocate phase | 1375 | * we skip the allocate phase |
1377 | */ | 1376 | */ |
1378 | pcibios_allocate_bus_resources(&pci_root_buses); | 1377 | list_for_each_entry(b, &pci_root_buses, node) |
1378 | pcibios_allocate_bus_resources(b); | ||
1379 | 1379 | ||
1380 | if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) { | 1380 | if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) { |
1381 | pcibios_allocate_resources(0); | 1381 | pcibios_allocate_resources(0); |
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 21a6d55418f1..31481dc485de 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) | |||
189 | { | 189 | { |
190 | struct pci_controller *phb; | 190 | struct pci_controller *phb; |
191 | int primary; | 191 | int primary; |
192 | struct pci_bus *b; | ||
192 | 193 | ||
193 | primary = list_empty(&hose_list); | 194 | primary = list_empty(&hose_list); |
194 | phb = pcibios_alloc_controller(dn); | 195 | phb = pcibios_alloc_controller(dn); |
@@ -203,6 +204,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | |||
203 | eeh_add_device_tree_early(dn); | 204 | eeh_add_device_tree_early(dn); |
204 | 205 | ||
205 | scan_phb(phb); | 206 | scan_phb(phb); |
207 | pcibios_allocate_bus_resources(phb->bus); | ||
206 | pcibios_fixup_new_pci_devices(phb->bus); | 208 | pcibios_fixup_new_pci_devices(phb->bus); |
207 | pci_bus_add_devices(phb->bus); | 209 | pci_bus_add_devices(phb->bus); |
208 | eeh_add_device_tree_late(phb->bus); | 210 | eeh_add_device_tree_late(phb->bus); |