]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | Subject: Fix DLPAR |
2 | From: Benjamin Herrenschmidt <benh@kernel.crashing.org> | |
3 | References: 439491 | |
4 | ||
5 | Signed-off-by: Olaf Hering <olh@suse.de> | |
6 | --- | |
7 | arch/powerpc/include/asm/pci-bridge.h | 4 | |
8 | arch/powerpc/include/asm/pci.h | 10 + | |
9 | arch/powerpc/kernel/pci-common.c | 124 ++++++++++++---------- | |
10 | arch/powerpc/kernel/pci_32.c | 6 - | |
11 | arch/powerpc/kernel/pci_64.c | 27 +++- | |
12 | arch/powerpc/kernel/rtas_pci.c | 48 -------- | |
13 | arch/powerpc/platforms/pseries/eeh.c | 44 ++++--- | |
14 | arch/powerpc/platforms/pseries/pci_dlpar.c | 163 +++++++++++++++-------------- | |
15 | drivers/pci/hotplug/rpadlpar_core.c | 49 +++++--- | |
16 | drivers/pci/hotplug/rpaphp_slot.c | 4 | |
17 | 10 files changed, 245 insertions(+), 234 deletions(-) | |
18 | ||
19 | --- a/arch/powerpc/include/asm/pci-bridge.h | |
20 | +++ b/arch/powerpc/include/asm/pci-bridge.h | |
21 | @@ -234,9 +234,7 @@ extern void pcibios_remove_pci_devices(s | |
22 | ||
23 | /** Discover new pci devices under this bus, and add them */ | |
24 | extern void pcibios_add_pci_devices(struct pci_bus *bus); | |
25 | -extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus); | |
26 | - | |
27 | -extern int pcibios_remove_root_bus(struct pci_controller *phb); | |
28 | +extern void pcibios_finish_adding_new_bus(struct pci_bus *bus); | |
29 | ||
30 | static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus) | |
31 | { | |
32 | --- a/arch/powerpc/include/asm/pci.h | |
33 | +++ b/arch/powerpc/include/asm/pci.h | |
34 | @@ -201,6 +201,7 @@ extern void pcibios_allocate_bus_resourc | |
35 | extern void pcibios_resource_survey(void); | |
36 | ||
37 | extern struct pci_controller *init_phb_dynamic(struct device_node *dn); | |
38 | +extern int remove_phb_dynamic(struct pci_controller *phb); | |
39 | ||
40 | extern struct pci_dev *of_create_pci_dev(struct device_node *node, | |
41 | struct pci_bus *bus, int devfn); | |
42 | @@ -208,7 +209,8 @@ extern struct pci_dev *of_create_pci_dev | |
43 | extern void of_scan_pci_bridge(struct device_node *node, | |
44 | struct pci_dev *dev); | |
45 | ||
46 | -extern void of_scan_bus(struct device_node *node, struct pci_bus *bus); | |
47 | +extern void of_scan_bus(struct device_node *node, struct pci_bus *bus, | |
48 | + int rescan_existing); | |
49 | ||
50 | extern int pci_read_irq_line(struct pci_dev *dev); | |
51 | ||
52 | @@ -223,8 +225,10 @@ extern void pci_resource_to_user(const s | |
53 | const struct resource *rsrc, | |
54 | resource_size_t *start, resource_size_t *end); | |
55 | ||
56 | -extern void pcibios_do_bus_setup(struct pci_bus *bus); | |
57 | -extern void pcibios_fixup_of_probed_bus(struct pci_bus *bus); | |
58 | +extern void pcibios_do_bus_setup_self(struct pci_bus *bus); | |
59 | +extern void pcibios_do_bus_setup_devices(struct pci_bus *bus); | |
60 | +extern void pcibios_fixup_bus_self(struct pci_bus *bus); | |
61 | +extern void pcibios_fixup_bus_devices(struct pci_bus *bus); | |
62 | ||
63 | #endif /* __KERNEL__ */ | |
64 | #endif /* __ASM_POWERPC_PCI_H */ | |
65 | --- a/arch/powerpc/kernel/pci_32.c | |
66 | +++ b/arch/powerpc/kernel/pci_32.c | |
67 | @@ -418,7 +418,7 @@ static int __init pcibios_init(void) | |
68 | ||
69 | subsys_initcall(pcibios_init); | |
70 | ||
71 | -void __devinit pcibios_do_bus_setup(struct pci_bus *bus) | |
72 | +void __devinit pcibios_do_bus_setup_self(struct pci_bus *bus) | |
73 | { | |
74 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | |
75 | unsigned long io_offset; | |
76 | @@ -459,6 +459,10 @@ void __devinit pcibios_do_bus_setup(stru | |
77 | } | |
78 | } | |
79 | ||
80 | +void __devinit pcibios_do_bus_setup_devices(struct pci_bus *bus) | |
81 | +{ | |
82 | +} | |
83 | + | |
84 | /* the next one is stolen from the alpha port... */ | |
85 | void __init | |
86 | pcibios_update_irq(struct pci_dev *dev, int irq) | |
87 | --- a/arch/powerpc/kernel/pci_64.c | |
88 | +++ b/arch/powerpc/kernel/pci_64.c | |
89 | @@ -225,14 +225,16 @@ struct pci_dev *of_create_pci_dev(struct | |
90 | EXPORT_SYMBOL(of_create_pci_dev); | |
91 | ||
92 | void __devinit of_scan_bus(struct device_node *node, | |
93 | - struct pci_bus *bus) | |
94 | + struct pci_bus *bus, | |
95 | + int rescan_existing) | |
96 | { | |
97 | struct device_node *child; | |
98 | const u32 *reg; | |
99 | int reglen, devfn; | |
100 | struct pci_dev *dev; | |
101 | ||
102 | - DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number); | |
103 | + DBG("of_scan_bus(%s) %s bus no %d... \n", node->full_name, | |
104 | + rescan_existing ? "existing" : "new", bus->number); | |
105 | ||
106 | /* Scan direct children */ | |
107 | for_each_child_of_node(node, child) { | |
108 | @@ -249,8 +251,12 @@ void __devinit of_scan_bus(struct device | |
109 | DBG(" dev header type: %x\n", dev->hdr_type); | |
110 | } | |
111 | ||
112 | - /* Ally all fixups */ | |
113 | - pcibios_fixup_of_probed_bus(bus); | |
114 | + /* Apply all fixups necessary. We don't fixup the bus "self" | |
115 | + * for an existing bridge that is being rescanned | |
116 | + */ | |
117 | + if (!rescan_existing) | |
118 | + pcibios_fixup_bus_self(bus); | |
119 | + pcibios_fixup_bus_devices(bus); | |
120 | ||
121 | /* Now scan child busses */ | |
122 | list_for_each_entry(dev, &bus->devices, bus_list) { | |
123 | @@ -346,7 +352,7 @@ void __devinit of_scan_pci_bridge(struct | |
124 | DBG(" probe mode: %d\n", mode); | |
125 | ||
126 | if (mode == PCI_PROBE_DEVTREE) | |
127 | - of_scan_bus(node, bus); | |
128 | + of_scan_bus(node, bus, 0); | |
129 | else if (mode == PCI_PROBE_NORMAL) | |
130 | pci_scan_child_bus(bus); | |
131 | } | |
132 | @@ -396,7 +402,7 @@ void __devinit scan_phb(struct pci_contr | |
133 | DBG(" probe mode: %d\n", mode); | |
134 | if (mode == PCI_PROBE_DEVTREE) { | |
135 | bus->subordinate = hose->last_busno; | |
136 | - of_scan_bus(node, bus); | |
137 | + of_scan_bus(node, bus, 0); | |
138 | } | |
139 | ||
140 | if (mode == PCI_PROBE_NORMAL) | |
141 | @@ -568,12 +574,15 @@ void __devinit pcibios_setup_new_device( | |
142 | } | |
143 | EXPORT_SYMBOL(pcibios_setup_new_device); | |
144 | ||
145 | -void __devinit pcibios_do_bus_setup(struct pci_bus *bus) | |
146 | +void __devinit pcibios_do_bus_setup_self(struct pci_bus *bus) | |
147 | { | |
148 | - struct pci_dev *dev; | |
149 | - | |
150 | if (ppc_md.pci_dma_bus_setup) | |
151 | ppc_md.pci_dma_bus_setup(bus); | |
152 | +} | |
153 | + | |
154 | +void __devinit pcibios_do_bus_setup_devices(struct pci_bus *bus) | |
155 | +{ | |
156 | + struct pci_dev *dev; | |
157 | ||
158 | list_for_each_entry(dev, &bus->devices, bus_list) | |
159 | pcibios_setup_new_device(dev); | |
160 | --- a/arch/powerpc/kernel/pci-common.c | |
161 | +++ b/arch/powerpc/kernel/pci-common.c | |
162 | @@ -789,63 +789,78 @@ static void __devinit pcibios_fixup_reso | |
163 | } | |
164 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); | |
165 | ||
166 | -static void __devinit __pcibios_fixup_bus(struct pci_bus *bus) | |
167 | +void __devinit pcibios_fixup_bus_self(struct pci_bus *bus) | |
168 | { | |
169 | struct pci_controller *hose = pci_bus_to_host(bus); | |
170 | struct pci_dev *dev = bus->self; | |
171 | + struct resource *res; | |
172 | + int i; | |
173 | ||
174 | - pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB"); | |
175 | + pr_debug("PCI: Fixup bus resources %d (%s)\n", | |
176 | + bus->number, dev ? pci_name(dev) : "PHB"); | |
177 | ||
178 | /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for | |
179 | * now differently between 32 and 64 bits. | |
180 | */ | |
181 | - if (dev != NULL) { | |
182 | - struct resource *res; | |
183 | - int i; | |
184 | - | |
185 | - for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { | |
186 | - if ((res = bus->resource[i]) == NULL) | |
187 | - continue; | |
188 | - if (!res->flags) | |
189 | - continue; | |
190 | - if (i >= 3 && bus->self->transparent) | |
191 | - continue; | |
192 | - /* On PowerMac, Apple leaves bridge windows open over | |
193 | - * an inaccessible region of memory space (0...fffff) | |
194 | - * which is somewhat bogus, but that's what they think | |
195 | - * means disabled... | |
196 | - * | |
197 | - * We clear those to force them to be reallocated later | |
198 | - * | |
199 | - * We detect such regions by the fact that the base is | |
200 | - * equal to the pci_mem_offset of the host bridge and | |
201 | - * their size is smaller than 1M. | |
202 | - */ | |
203 | - if (res->flags & IORESOURCE_MEM && | |
204 | - res->start == hose->pci_mem_offset && | |
205 | - res->end < 0x100000) { | |
206 | - printk(KERN_INFO | |
207 | - "PCI: Closing bogus Apple Firmware" | |
208 | - " region %d on bus 0x%02x\n", | |
209 | - i, bus->number); | |
210 | - res->flags = 0; | |
211 | - continue; | |
212 | - } | |
213 | + if (dev == NULL) | |
214 | + goto host_bridge; | |
215 | ||
216 | - pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n", | |
217 | - pci_name(dev), i, | |
218 | - (unsigned long long)res->start,\ | |
219 | - (unsigned long long)res->end, | |
220 | - (unsigned int)res->flags); | |
221 | + for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { | |
222 | + if ((res = bus->resource[i]) == NULL) | |
223 | + continue; | |
224 | + if (!res->flags) | |
225 | + continue; | |
226 | + if (i >= 3 && bus->self->transparent) | |
227 | + continue; | |
228 | ||
229 | - fixup_resource(res, dev); | |
230 | + /* On PowerMac, Apple leaves bridge windows open over | |
231 | + * an inaccessible region of memory space (0...fffff) | |
232 | + * which is somewhat bogus, but that's what they think | |
233 | + * means disabled... | |
234 | + * | |
235 | + * We clear those to force them to be reallocated later | |
236 | + * | |
237 | + * We detect such regions by the fact that the base is | |
238 | + * equal to the pci_mem_offset of the host bridge and | |
239 | + * their size is smaller than 1M. | |
240 | + */ | |
241 | + if (res->flags & IORESOURCE_MEM && | |
242 | + res->start == hose->pci_mem_offset && | |
243 | + res->end < 0x100000) { | |
244 | + printk(KERN_INFO | |
245 | + "PCI: Closing bogus Apple Firmware" | |
246 | + " region %d on bus 0x%02x\n", | |
247 | + i, bus->number); | |
248 | + res->flags = 0; | |
249 | + continue; | |
250 | } | |
251 | + | |
252 | + pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n", | |
253 | + pci_name(dev), i, | |
254 | + (unsigned long long)res->start,\ | |
255 | + (unsigned long long)res->end, | |
256 | + (unsigned int)res->flags); | |
257 | + | |
258 | + fixup_resource(res, dev); | |
259 | } | |
260 | ||
261 | +host_bridge: | |
262 | + | |
263 | + /* Additional setup that is different between 32 and 64 bits for now */ | |
264 | + pcibios_do_bus_setup_self(bus); | |
265 | +} | |
266 | + | |
267 | +void __devinit pcibios_fixup_bus_devices(struct pci_bus *bus) | |
268 | +{ | |
269 | + struct pci_dev *dev = bus->self; | |
270 | + | |
271 | + pr_debug("PCI: Fixup bus devices %d (%s)\n", | |
272 | + bus->number, dev ? pci_name(dev) : "PHB"); | |
273 | + | |
274 | /* Additional setup that is different between 32 and 64 bits for now */ | |
275 | - pcibios_do_bus_setup(bus); | |
276 | + pcibios_do_bus_setup_devices(bus); | |
277 | ||
278 | - /* Platform specific bus fixups */ | |
279 | + /* Platform specific bus fixups (XXX Get rid of these !) */ | |
280 | if (ppc_md.pcibios_fixup_bus) | |
281 | ppc_md.pcibios_fixup_bus(bus); | |
282 | ||
283 | @@ -864,19 +879,11 @@ void __devinit pcibios_fixup_bus(struct | |
284 | */ | |
285 | if (bus->self != NULL) | |
286 | pci_read_bridge_bases(bus); | |
287 | - __pcibios_fixup_bus(bus); | |
288 | + pcibios_fixup_bus_self(bus); | |
289 | + pcibios_fixup_bus_devices(bus); | |
290 | } | |
291 | EXPORT_SYMBOL(pcibios_fixup_bus); | |
292 | ||
293 | -/* When building a bus from the OF tree rather than probing, we need a | |
294 | - * slightly different version of the fixup which doesn't read the | |
295 | - * bridge bases using config space accesses | |
296 | - */ | |
297 | -void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus) | |
298 | -{ | |
299 | - __pcibios_fixup_bus(bus); | |
300 | -} | |
301 | - | |
302 | static int skip_isa_ioresource_align(struct pci_dev *dev) | |
303 | { | |
304 | if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) && | |
305 | @@ -992,9 +999,12 @@ void pcibios_allocate_bus_resources(stru | |
306 | int i; | |
307 | struct resource *res, *pr; | |
308 | ||
309 | + DBG("PCI: Allocating bus resources for %04x:%02x...\n", | |
310 | + pci_domain_nr(bus), bus->number); | |
311 | + | |
312 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { | |
313 | if ((res = bus->resource[i]) == NULL || !res->flags | |
314 | - || res->start > res->end) | |
315 | + || res->start > res->end || res->parent) | |
316 | continue; | |
317 | if (bus->parent == NULL) | |
318 | pr = (res->flags & IORESOURCE_IO) ? | |
319 | @@ -1047,6 +1057,7 @@ clear_resource: | |
320 | list_for_each_entry(b, &bus->children, node) | |
321 | pcibios_allocate_bus_resources(b); | |
322 | } | |
323 | +EXPORT_SYMBOL_GPL(pcibios_allocate_bus_resources); | |
324 | ||
325 | static inline void __devinit alloc_resource(struct pci_dev *dev, int idx) | |
326 | { | |
327 | @@ -1157,6 +1168,13 @@ void __devinit pcibios_claim_one_bus(str | |
328 | ||
329 | if (r->parent || !r->start || !r->flags) | |
330 | continue; | |
331 | + | |
332 | + DBG("PCI: Claiming %s: Resource %d: %016llx..%016llx [%x]\n", | |
333 | + pci_name(dev), i, | |
334 | + (unsigned long long)r->start, | |
335 | + (unsigned long long)r->end, | |
336 | + (unsigned int)r->flags); | |
337 | + | |
338 | pci_claim_resource(dev, i); | |
339 | } | |
340 | } | |
341 | --- a/arch/powerpc/kernel/rtas_pci.c | |
342 | +++ b/arch/powerpc/kernel/rtas_pci.c | |
343 | @@ -301,51 +301,3 @@ void __init find_and_init_phbs(void) | |
344 | #endif /* CONFIG_PPC32 */ | |
345 | } | |
346 | } | |
347 | - | |
348 | -/* RPA-specific bits for removing PHBs */ | |
349 | -int pcibios_remove_root_bus(struct pci_controller *phb) | |
350 | -{ | |
351 | - struct pci_bus *b = phb->bus; | |
352 | - struct resource *res; | |
353 | - int rc, i; | |
354 | - | |
355 | - res = b->resource[0]; | |
356 | - if (!res->flags) { | |
357 | - printk(KERN_ERR "%s: no IO resource for PHB %s\n", __func__, | |
358 | - b->name); | |
359 | - return 1; | |
360 | - } | |
361 | - | |
362 | - rc = pcibios_unmap_io_space(b); | |
363 | - if (rc) { | |
364 | - printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", | |
365 | - __func__, b->name); | |
366 | - return 1; | |
367 | - } | |
368 | - | |
369 | - if (release_resource(res)) { | |
370 | - printk(KERN_ERR "%s: failed to release IO on bus %s\n", | |
371 | - __func__, b->name); | |
372 | - return 1; | |
373 | - } | |
374 | - | |
375 | - for (i = 1; i < 3; ++i) { | |
376 | - res = b->resource[i]; | |
377 | - if (!res->flags && i == 0) { | |
378 | - printk(KERN_ERR "%s: no MEM resource for PHB %s\n", | |
379 | - __func__, b->name); | |
380 | - return 1; | |
381 | - } | |
382 | - if (res->flags && release_resource(res)) { | |
383 | - printk(KERN_ERR | |
384 | - "%s: failed to release IO %d on bus %s\n", | |
385 | - __func__, i, b->name); | |
386 | - return 1; | |
387 | - } | |
388 | - } | |
389 | - | |
390 | - pcibios_free_controller(phb); | |
391 | - | |
392 | - return 0; | |
393 | -} | |
394 | -EXPORT_SYMBOL(pcibios_remove_root_bus); | |
395 | --- a/arch/powerpc/platforms/pseries/eeh.c | |
396 | +++ b/arch/powerpc/platforms/pseries/eeh.c | |
397 | @@ -21,6 +21,8 @@ | |
398 | * Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com> | |
399 | */ | |
400 | ||
401 | +#undef DEBUG | |
402 | + | |
403 | #include <linux/delay.h> | |
404 | #include <linux/init.h> | |
405 | #include <linux/list.h> | |
406 | @@ -488,10 +490,8 @@ int eeh_dn_check_failure(struct device_n | |
407 | if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || | |
408 | pdn->eeh_mode & EEH_MODE_NOCHECK) { | |
409 | ignored_check++; | |
410 | -#ifdef DEBUG | |
411 | - printk ("EEH:ignored check (%x) for %s %s\n", | |
412 | - pdn->eeh_mode, pci_name (dev), dn->full_name); | |
413 | -#endif | |
414 | + pr_debug("EEH: Ignored check (%x) for %s %s\n", | |
415 | + pdn->eeh_mode, pci_name (dev), dn->full_name); | |
416 | return 0; | |
417 | } | |
418 | ||
419 | @@ -1014,10 +1014,9 @@ static void *early_enable_eeh(struct dev | |
420 | eeh_subsystem_enabled = 1; | |
421 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; | |
422 | ||
423 | -#ifdef DEBUG | |
424 | - printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n", | |
425 | - dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr); | |
426 | -#endif | |
427 | + pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", | |
428 | + dn->full_name, pdn->eeh_config_addr, | |
429 | + pdn->eeh_pe_config_addr); | |
430 | } else { | |
431 | ||
432 | /* This device doesn't support EEH, but it may have an | |
433 | @@ -1161,13 +1160,17 @@ static void eeh_add_device_late(struct p | |
434 | if (!dev || !eeh_subsystem_enabled) | |
435 | return; | |
436 | ||
437 | -#ifdef DEBUG | |
438 | - printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev)); | |
439 | -#endif | |
440 | + pr_debug("EEH: Adding device %s\n", pci_name(dev)); | |
441 | ||
442 | - pci_dev_get (dev); | |
443 | dn = pci_device_to_OF_node(dev); | |
444 | pdn = PCI_DN(dn); | |
445 | + if (pdn->pcidev == dev) { | |
446 | + pr_debug("EEH: Already referenced !\n"); | |
447 | + return; | |
448 | + } | |
449 | + WARN_ON(pdn->pcidev); | |
450 | + | |
451 | + pci_dev_get (dev); | |
452 | pdn->pcidev = dev; | |
453 | ||
454 | pci_addr_cache_insert_device(dev); | |
455 | @@ -1206,17 +1209,18 @@ static void eeh_remove_device(struct pci | |
456 | return; | |
457 | ||
458 | /* Unregister the device with the EEH/PCI address search system */ | |
459 | -#ifdef DEBUG | |
460 | - printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); | |
461 | -#endif | |
462 | - pci_addr_cache_remove_device(dev); | |
463 | - eeh_sysfs_remove_device(dev); | |
464 | + pr_debug("EEH: Removing device %s\n", pci_name(dev)); | |
465 | ||
466 | dn = pci_device_to_OF_node(dev); | |
467 | - if (PCI_DN(dn)->pcidev) { | |
468 | - PCI_DN(dn)->pcidev = NULL; | |
469 | - pci_dev_put (dev); | |
470 | + if (PCI_DN(dn)->pcidev == NULL) { | |
471 | + pr_debug("EEH: Not referenced !\n"); | |
472 | + return; | |
473 | } | |
474 | + PCI_DN(dn)->pcidev = NULL; | |
475 | + pci_dev_put (dev); | |
476 | + | |
477 | + pci_addr_cache_remove_device(dev); | |
478 | + eeh_sysfs_remove_device(dev); | |
479 | } | |
480 | ||
481 | void eeh_remove_bus_device(struct pci_dev *dev) | |
482 | --- a/arch/powerpc/platforms/pseries/pci_dlpar.c | |
483 | +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c | |
484 | @@ -25,6 +25,8 @@ | |
485 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
486 | */ | |
487 | ||
488 | +#undef DEBUG | |
489 | + | |
490 | #include <linux/pci.h> | |
491 | #include <asm/pci-bridge.h> | |
492 | #include <asm/ppc-pci.h> | |
493 | @@ -69,73 +71,41 @@ EXPORT_SYMBOL_GPL(pcibios_find_pci_bus); | |
494 | * Remove all of the PCI devices under this bus both from the | |
495 | * linux pci device tree, and from the powerpc EEH address cache. | |
496 | */ | |
497 | -void | |
498 | -pcibios_remove_pci_devices(struct pci_bus *bus) | |
499 | +void pcibios_remove_pci_devices(struct pci_bus *bus) | |
500 | { | |
501 | struct pci_dev *dev, *tmp; | |
502 | + struct pci_bus *child_bus; | |
503 | ||
504 | + /* First go down child busses */ | |
505 | + list_for_each_entry(child_bus, &bus->children, node) | |
506 | + pcibios_remove_pci_devices(child_bus); | |
507 | + | |
508 | + pr_debug("PCI: Removing devices on bus %04x:%02x\n", | |
509 | + pci_domain_nr(bus), bus->number); | |
510 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { | |
511 | + pr_debug(" * Removing %s...\n", pci_name(dev)); | |
512 | eeh_remove_bus_device(dev); | |
513 | pci_remove_bus_device(dev); | |
514 | } | |
515 | } | |
516 | EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); | |
517 | ||
518 | -/* Must be called before pci_bus_add_devices */ | |
519 | -void | |
520 | -pcibios_fixup_new_pci_devices(struct pci_bus *bus) | |
521 | -{ | |
522 | - struct pci_dev *dev; | |
523 | - | |
524 | - list_for_each_entry(dev, &bus->devices, bus_list) { | |
525 | - /* Skip already-added devices */ | |
526 | - if (!dev->is_added) { | |
527 | - int i; | |
528 | - | |
529 | - /* Fill device archdata and setup iommu table */ | |
530 | - pcibios_setup_new_device(dev); | |
531 | - | |
532 | - pci_read_irq_line(dev); | |
533 | - for (i = 0; i < PCI_NUM_RESOURCES; i++) { | |
534 | - struct resource *r = &dev->resource[i]; | |
535 | - | |
536 | - if (r->parent || !r->start || !r->flags) | |
537 | - continue; | |
538 | - pci_claim_resource(dev, i); | |
539 | - } | |
540 | - } | |
541 | - } | |
542 | -} | |
543 | -EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices); | |
544 | - | |
545 | -static int | |
546 | -pcibios_pci_config_bridge(struct pci_dev *dev) | |
547 | +void pcibios_finish_adding_new_bus(struct pci_bus *bus) | |
548 | { | |
549 | - u8 sec_busno; | |
550 | - struct pci_bus *child_bus; | |
551 | - | |
552 | - /* Get busno of downstream bus */ | |
553 | - pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno); | |
554 | + pr_debug("PCI: Finishing adding hotplug bus %04x:%02x\n", | |
555 | + pci_domain_nr(bus), bus->number); | |
556 | ||
557 | - /* Add to children of PCI bridge dev->bus */ | |
558 | - child_bus = pci_add_new_bus(dev->bus, dev, sec_busno); | |
559 | - if (!child_bus) { | |
560 | - printk (KERN_ERR "%s: could not add second bus\n", __func__); | |
561 | - return -EIO; | |
562 | - } | |
563 | - sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number); | |
564 | - | |
565 | - pci_scan_child_bus(child_bus); | |
566 | + /* Allocate bus and devices resources */ | |
567 | + pcibios_allocate_bus_resources(bus); | |
568 | + pcibios_claim_one_bus(bus); | |
569 | ||
570 | - /* Fixup new pci devices */ | |
571 | - pcibios_fixup_new_pci_devices(child_bus); | |
572 | + /* Add new devices to global lists. Register in proc, sysfs. */ | |
573 | + pci_bus_add_devices(bus); | |
574 | ||
575 | - /* Make the discovered devices available */ | |
576 | - pci_bus_add_devices(child_bus); | |
577 | - | |
578 | - eeh_add_device_tree_late(child_bus); | |
579 | - return 0; | |
580 | + /* Fixup EEH */ | |
581 | + eeh_add_device_tree_late(bus); | |
582 | } | |
583 | +EXPORT_SYMBOL_GPL(pcibios_finish_adding_new_bus); | |
584 | ||
585 | /** | |
586 | * pcibios_add_pci_devices - adds new pci devices to bus | |
587 | @@ -147,10 +117,9 @@ pcibios_pci_config_bridge(struct pci_dev | |
588 | * is how this routine differs from other, similar pcibios | |
589 | * routines.) | |
590 | */ | |
591 | -void | |
592 | -pcibios_add_pci_devices(struct pci_bus * bus) | |
593 | +void pcibios_add_pci_devices(struct pci_bus * bus) | |
594 | { | |
595 | - int slotno, num, mode; | |
596 | + int slotno, num, mode, pass, max; | |
597 | struct pci_dev *dev; | |
598 | struct device_node *dn = pci_bus_to_OF_node(bus); | |
599 | ||
600 | @@ -162,25 +131,24 @@ pcibios_add_pci_devices(struct pci_bus * | |
601 | ||
602 | if (mode == PCI_PROBE_DEVTREE) { | |
603 | /* use ofdt-based probe */ | |
604 | - of_scan_bus(dn, bus); | |
605 | - if (!list_empty(&bus->devices)) { | |
606 | - pcibios_fixup_new_pci_devices(bus); | |
607 | - pci_bus_add_devices(bus); | |
608 | - eeh_add_device_tree_late(bus); | |
609 | - } | |
610 | + of_scan_bus(dn, bus, 1); | |
611 | + if (!list_empty(&bus->devices)) | |
612 | + pcibios_finish_adding_new_bus(bus); | |
613 | } else if (mode == PCI_PROBE_NORMAL) { | |
614 | /* use legacy probe */ | |
615 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); | |
616 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); | |
617 | - if (num) { | |
618 | - pcibios_fixup_new_pci_devices(bus); | |
619 | - pci_bus_add_devices(bus); | |
620 | - eeh_add_device_tree_late(bus); | |
621 | + if (!num) | |
622 | + return; | |
623 | + pcibios_fixup_bus_devices(bus); | |
624 | + max = bus->secondary; | |
625 | + for (pass=0; pass < 2; pass++) | |
626 | + list_for_each_entry(dev, &bus->devices, bus_list) { | |
627 | + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | |
628 | + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | |
629 | + max = pci_scan_bridge(bus, dev, max, pass); | |
630 | } | |
631 | - | |
632 | - list_for_each_entry(dev, &bus->devices, bus_list) | |
633 | - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) | |
634 | - pcibios_pci_config_bridge(dev); | |
635 | + pcibios_finish_adding_new_bus(bus); | |
636 | } | |
637 | } | |
638 | EXPORT_SYMBOL_GPL(pcibios_add_pci_devices); | |
639 | @@ -189,7 +157,8 @@ struct pci_controller * __devinit init_p | |
640 | { | |
641 | struct pci_controller *phb; | |
642 | int primary; | |
643 | - struct pci_bus *b; | |
644 | + | |
645 | + pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name); | |
646 | ||
647 | primary = list_empty(&hose_list); | |
648 | phb = pcibios_alloc_controller(dn); | |
649 | @@ -204,11 +173,57 @@ struct pci_controller * __devinit init_p | |
650 | eeh_add_device_tree_early(dn); | |
651 | ||
652 | scan_phb(phb); | |
653 | - pcibios_allocate_bus_resources(phb->bus); | |
654 | - pcibios_fixup_new_pci_devices(phb->bus); | |
655 | - pci_bus_add_devices(phb->bus); | |
656 | - eeh_add_device_tree_late(phb->bus); | |
657 | + pcibios_finish_adding_new_bus(phb->bus); | |
658 | ||
659 | return phb; | |
660 | } | |
661 | EXPORT_SYMBOL_GPL(init_phb_dynamic); | |
662 | + | |
663 | + | |
664 | + | |
665 | + | |
666 | +/* RPA-specific bits for removing PHBs */ | |
667 | +int remove_phb_dynamic(struct pci_controller *phb) | |
668 | +{ | |
669 | + struct pci_bus *b = phb->bus; | |
670 | + struct resource *res; | |
671 | + int rc, i; | |
672 | + | |
673 | + pr_debug("PCI: Removing PHB %04x:%02x... \n", pci_domain_nr(b), b->number); | |
674 | + | |
675 | + /* We -know- there aren't any child devices anymore at this stage | |
676 | + * and thus, we can safely unmap the IO space as it's not in use | |
677 | + */ | |
678 | + res = &phb->io_resource; | |
679 | + if (res->flags & IORESOURCE_IO) { | |
680 | + rc = pcibios_unmap_io_space(b); | |
681 | + if (rc) { | |
682 | + printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", | |
683 | + __func__, b->name); | |
684 | + return 1; | |
685 | + } | |
686 | + } | |
687 | + | |
688 | + /* Unregister the bridge device from sysfs and remove the PCI bus */ | |
689 | + device_unregister(b->bridge); | |
690 | + phb->bus = NULL; | |
691 | + pci_remove_bus(b); | |
692 | + | |
693 | + /* Now release the IO resource */ | |
694 | + if (res->flags & IORESOURCE_IO) | |
695 | + release_resource(res); | |
696 | + | |
697 | + /* Release memory resources */ | |
698 | + for (i = 0; i < 3; ++i) { | |
699 | + res = &phb->mem_resources[i]; | |
700 | + if (!(res->flags & IORESOURCE_MEM)) | |
701 | + continue; | |
702 | + release_resource(res); | |
703 | + } | |
704 | + | |
705 | + /* Free pci_controller data structure */ | |
706 | + pcibios_free_controller(phb); | |
707 | + | |
708 | + return 0; | |
709 | +} | |
710 | +EXPORT_SYMBOL_GPL(remove_phb_dynamic); | |
711 | --- a/drivers/pci/hotplug/rpadlpar_core.c | |
712 | +++ b/drivers/pci/hotplug/rpadlpar_core.c | |
713 | @@ -14,6 +14,8 @@ | |
714 | * as published by the Free Software Foundation; either version | |
715 | * 2 of the License, or (at your option) any later version. | |
716 | */ | |
717 | +#undef DEBUG | |
718 | + | |
719 | #include <linux/init.h> | |
720 | #include <linux/pci.h> | |
721 | #include <linux/string.h> | |
722 | @@ -155,16 +157,15 @@ static void dlpar_pci_add_bus(struct dev | |
723 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | |
724 | of_scan_pci_bridge(dn, dev); | |
725 | ||
726 | - pcibios_fixup_new_pci_devices(dev->subordinate); | |
727 | - | |
728 | - /* Claim new bus resources */ | |
729 | - pcibios_claim_one_bus(dev->bus); | |
730 | - | |
731 | /* Map IO space for child bus, which may or may not succeed */ | |
732 | pcibios_map_io_space(dev->subordinate); | |
733 | ||
734 | - /* Add new devices to global lists. Register in proc, sysfs. */ | |
735 | - pci_bus_add_devices(phb->bus); | |
736 | + /* Finish adding it : resource allocation, adding devices, etc... | |
737 | + * Note that we need to perform the finish pass on the -parent- | |
738 | + * bus of the EADS bridge so the bridge device itself gets | |
739 | + * properly added | |
740 | + */ | |
741 | + pcibios_finish_adding_new_bus(phb->bus); | |
742 | } | |
743 | ||
744 | static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) | |
745 | @@ -206,22 +207,19 @@ static int dlpar_add_pci_slot(char *drc_ | |
746 | static int dlpar_remove_root_bus(struct pci_controller *phb) | |
747 | { | |
748 | struct pci_bus *phb_bus; | |
749 | - int rc; | |
750 | ||
751 | phb_bus = phb->bus; | |
752 | + pr_debug("PCI: -> removing root bus %04x:%02x\n", | |
753 | + pci_domain_nr(phb_bus), phb_bus->number); | |
754 | + | |
755 | + /* We cannot to remove a root bus that has children */ | |
756 | if (!(list_empty(&phb_bus->children) && | |
757 | list_empty(&phb_bus->devices))) { | |
758 | + pr_debug("PCI: PHB removal failed, bus not empty !\n"); | |
759 | return -EBUSY; | |
760 | } | |
761 | ||
762 | - rc = pcibios_remove_root_bus(phb); | |
763 | - if (rc) | |
764 | - return -EIO; | |
765 | - | |
766 | - device_unregister(phb_bus->bridge); | |
767 | - pci_remove_bus(phb_bus); | |
768 | - | |
769 | - return 0; | |
770 | + return remove_phb_dynamic(phb); | |
771 | } | |
772 | ||
773 | static int dlpar_remove_phb(char *drc_name, struct device_node *dn) | |
774 | @@ -233,6 +231,8 @@ static int dlpar_remove_phb(char *drc_na | |
775 | if (!pcibios_find_pci_bus(dn)) | |
776 | return -EINVAL; | |
777 | ||
778 | + pr_debug("PCI: Removing PHB %s...\n", dn->full_name); | |
779 | + | |
780 | /* If pci slot is hotplugable, use hotplug to remove it */ | |
781 | slot = find_php_slot(dn); | |
782 | if (slot) { | |
783 | @@ -378,25 +378,36 @@ int dlpar_remove_pci_slot(char *drc_name | |
784 | if (!bus) | |
785 | return -EINVAL; | |
786 | ||
787 | - /* If pci slot is hotplugable, use hotplug to remove it */ | |
788 | + pr_debug("PCI: Removing PCI slot below EADS bridge %s\n", | |
789 | + bus->self ? pci_name(bus->self) : "<!PHB!>"); | |
790 | + | |
791 | + /* If pci slot is hotplugable, remove hotplug data structures */ | |
792 | slot = find_php_slot(dn); | |
793 | if (slot) { | |
794 | + pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n", | |
795 | + pci_domain_nr(bus), bus->number); | |
796 | if (rpaphp_deregister_slot(slot)) { | |
797 | printk(KERN_ERR | |
798 | "%s: unable to remove hotplug slot %s\n", | |
799 | __func__, drc_name); | |
800 | return -EIO; | |
801 | } | |
802 | - } else | |
803 | - pcibios_remove_pci_devices(bus); | |
804 | + } | |
805 | + | |
806 | + /* Remove all devices below slot */ | |
807 | + pcibios_remove_pci_devices(bus); | |
808 | ||
809 | + /* Unmap PCI IO space */ | |
810 | if (pcibios_unmap_io_space(bus)) { | |
811 | printk(KERN_ERR "%s: failed to unmap bus range\n", | |
812 | __func__); | |
813 | return -ERANGE; | |
814 | } | |
815 | ||
816 | + /* Remove the EADS bridge device itself */ | |
817 | BUG_ON(!bus->self); | |
818 | + pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self)); | |
819 | + eeh_remove_bus_device(bus->self); | |
820 | pci_remove_bus_device(bus->self); | |
821 | return 0; | |
822 | } | |
823 | --- a/drivers/pci/hotplug/rpaphp_slot.c | |
824 | +++ b/drivers/pci/hotplug/rpaphp_slot.c | |
825 | @@ -145,9 +145,5 @@ int rpaphp_register_slot(struct slot *sl | |
826 | list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); | |
827 | info("Slot [%s] registered\n", slot->name); | |
828 | return 0; | |
829 | - | |
830 | -sysfs_fail: | |
831 | - pci_hp_deregister(php_slot); | |
832 | - return retval; | |
833 | } | |
834 |