aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-27 15:48:52 -0400
committerPaul Mackerras <paulus@samba.org>2008-11-05 17:31:52 -0500
commitfd6852c8fa060bd45c82a2593e18f933f6c6204f (patch)
treea0534b189bc6a791e93bce5894f892634aa4ab0c
parentb5ae5f911d221ad85090d6805ab9ab020f6e4703 (diff)
powerpc/pci: Fix various pseries PCI hotplug issues
The pseries PCI hotplug code has a number of issues, ranging from incorrect resource setup to crashes, depending on what is added, when, whether it contains a bridge, etc etc.... This fixes a whole bunch of these, while actually simplifying the code a bit, using more generic code in the process and factoring out common code between adding of a PHB, a slot or a device. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/include/asm/pci-bridge.h3
-rw-r--r--arch/powerpc/include/asm/pci.h5
-rw-r--r--arch/powerpc/kernel/pci-common.c41
-rw-r--r--arch/powerpc/kernel/rtas_pci.c48
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c163
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c69
6 files changed, 150 insertions, 179 deletions
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 2dfa8a3d8c76..fa8b3b724438 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -241,9 +241,6 @@ extern void pcibios_remove_pci_devices(struct pci_bus *bus);
241 241
242/** Discover new pci devices under this bus, and add them */ 242/** Discover new pci devices under this bus, and add them */
243extern void pcibios_add_pci_devices(struct pci_bus *bus); 243extern void pcibios_add_pci_devices(struct pci_bus *bus);
244extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus);
245
246extern int pcibios_remove_root_bus(struct pci_controller *phb);
247 244
248static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus) 245static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
249{ 246{
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 32e03e6d25c5..1c721a632d8e 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -204,15 +204,14 @@ static inline struct resource *pcibios_select_root(struct pci_dev *pdev,
204 return root; 204 return root;
205} 205}
206 206
207extern void pcibios_setup_new_device(struct pci_dev *dev);
208
209extern void pcibios_claim_one_bus(struct pci_bus *b); 207extern void pcibios_claim_one_bus(struct pci_bus *b);
210 208
211extern void pcibios_allocate_bus_resources(struct pci_bus *bus); 209extern void pcibios_finish_adding_to_bus(struct pci_bus *bus);
212 210
213extern void pcibios_resource_survey(void); 211extern void pcibios_resource_survey(void);
214 212
215extern struct pci_controller *init_phb_dynamic(struct device_node *dn); 213extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
214extern int remove_phb_dynamic(struct pci_controller *phb);
216 215
217extern struct pci_dev *of_create_pci_dev(struct device_node *node, 216extern struct pci_dev *of_create_pci_dev(struct device_node *node,
218 struct pci_bus *bus, int devfn); 217 struct pci_bus *bus, int devfn);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index f965397a6105..f3fd7eb90a7b 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -203,7 +203,7 @@ char __devinit *pcibios_setup(char *str)
203 return str; 203 return str;
204} 204}
205 205
206void __devinit pcibios_setup_new_device(struct pci_dev *dev) 206static void __devinit pcibios_setup_new_device(struct pci_dev *dev)
207{ 207{
208 struct dev_archdata *sd = &dev->dev.archdata; 208 struct dev_archdata *sd = &dev->dev.archdata;
209 209
@@ -221,7 +221,6 @@ void __devinit pcibios_setup_new_device(struct pci_dev *dev)
221 if (ppc_md.pci_dma_dev_setup) 221 if (ppc_md.pci_dma_dev_setup)
222 ppc_md.pci_dma_dev_setup(dev); 222 ppc_md.pci_dma_dev_setup(dev);
223} 223}
224EXPORT_SYMBOL(pcibios_setup_new_device);
225 224
226/* 225/*
227 * Reads the interrupt pin to determine if interrupt is use by card. 226 * Reads the interrupt pin to determine if interrupt is use by card.
@@ -1397,9 +1396,10 @@ void __init pcibios_resource_survey(void)
1397 1396
1398#ifdef CONFIG_HOTPLUG 1397#ifdef CONFIG_HOTPLUG
1399 1398
1400/* This is used by the pSeries hotplug driver to allocate resource 1399/* This is used by the PCI hotplug driver to allocate resource
1401 * of newly plugged busses. We can try to consolidate with the 1400 * of newly plugged busses. We can try to consolidate with the
1402 * rest of the code later, for now, keep it as-is 1401 * rest of the code later, for now, keep it as-is as our main
1402 * resource allocation function doesn't deal with sub-trees yet.
1403 */ 1403 */
1404void __devinit pcibios_claim_one_bus(struct pci_bus *bus) 1404void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
1405{ 1405{
@@ -1414,6 +1414,14 @@ void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
1414 1414
1415 if (r->parent || !r->start || !r->flags) 1415 if (r->parent || !r->start || !r->flags)
1416 continue; 1416 continue;
1417
1418 pr_debug("PCI: Claiming %s: "
1419 "Resource %d: %016llx..%016llx [%x]\n",
1420 pci_name(dev), i,
1421 (unsigned long long)r->start,
1422 (unsigned long long)r->end,
1423 (unsigned int)r->flags);
1424
1417 pci_claim_resource(dev, i); 1425 pci_claim_resource(dev, i);
1418 } 1426 }
1419 } 1427 }
@@ -1422,6 +1430,31 @@ void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
1422 pcibios_claim_one_bus(child_bus); 1430 pcibios_claim_one_bus(child_bus);
1423} 1431}
1424EXPORT_SYMBOL_GPL(pcibios_claim_one_bus); 1432EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);
1433
1434
1435/* pcibios_finish_adding_to_bus
1436 *
1437 * This is to be called by the hotplug code after devices have been
1438 * added to a bus, this include calling it for a PHB that is just
1439 * being added
1440 */
1441void pcibios_finish_adding_to_bus(struct pci_bus *bus)
1442{
1443 pr_debug("PCI: Finishing adding to hotplug bus %04x:%02x\n",
1444 pci_domain_nr(bus), bus->number);
1445
1446 /* Allocate bus and devices resources */
1447 pcibios_allocate_bus_resources(bus);
1448 pcibios_claim_one_bus(bus);
1449
1450 /* Add new devices to global lists. Register in proc, sysfs. */
1451 pci_bus_add_devices(bus);
1452
1453 /* Fixup EEH */
1454 eeh_add_device_tree_late(bus);
1455}
1456EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus);
1457
1425#endif /* CONFIG_HOTPLUG */ 1458#endif /* CONFIG_HOTPLUG */
1426 1459
1427int pcibios_enable_device(struct pci_dev *dev, int mask) 1460int pcibios_enable_device(struct pci_dev *dev, int mask)
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index 589a2797eac2..8869001ab5d7 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -301,51 +301,3 @@ void __init find_and_init_phbs(void)
301#endif /* CONFIG_PPC32 */ 301#endif /* CONFIG_PPC32 */
302 } 302 }
303} 303}
304
305/* RPA-specific bits for removing PHBs */
306int pcibios_remove_root_bus(struct pci_controller *phb)
307{
308 struct pci_bus *b = phb->bus;
309 struct resource *res;
310 int rc, i;
311
312 res = b->resource[0];
313 if (!res->flags) {
314 printk(KERN_ERR "%s: no IO resource for PHB %s\n", __func__,
315 b->name);
316 return 1;
317 }
318
319 rc = pcibios_unmap_io_space(b);
320 if (rc) {
321 printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
322 __func__, b->name);
323 return 1;
324 }
325
326 if (release_resource(res)) {
327 printk(KERN_ERR "%s: failed to release IO on bus %s\n",
328 __func__, b->name);
329 return 1;
330 }
331
332 for (i = 1; i < 3; ++i) {
333 res = b->resource[i];
334 if (!res->flags && i == 0) {
335 printk(KERN_ERR "%s: no MEM resource for PHB %s\n",
336 __func__, b->name);
337 return 1;
338 }
339 if (res->flags && release_resource(res)) {
340 printk(KERN_ERR
341 "%s: failed to release IO %d on bus %s\n",
342 __func__, i, b->name);
343 return 1;
344 }
345 }
346
347 pcibios_free_controller(phb);
348
349 return 0;
350}
351EXPORT_SYMBOL(pcibios_remove_root_bus);
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index 7190493e9bdc..5e1ed3d60ee5 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -25,6 +25,8 @@
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */ 26 */
27 27
28#undef DEBUG
29
28#include <linux/pci.h> 30#include <linux/pci.h>
29#include <asm/pci-bridge.h> 31#include <asm/pci-bridge.h>
30#include <asm/ppc-pci.h> 32#include <asm/ppc-pci.h>
@@ -69,74 +71,25 @@ EXPORT_SYMBOL_GPL(pcibios_find_pci_bus);
69 * Remove all of the PCI devices under this bus both from the 71 * Remove all of the PCI devices under this bus both from the
70 * linux pci device tree, and from the powerpc EEH address cache. 72 * linux pci device tree, and from the powerpc EEH address cache.
71 */ 73 */
72void 74void pcibios_remove_pci_devices(struct pci_bus *bus)
73pcibios_remove_pci_devices(struct pci_bus *bus)
74{ 75{
75 struct pci_dev *dev, *tmp; 76 struct pci_dev *dev, *tmp;
77 struct pci_bus *child_bus;
78
79 /* First go down child busses */
80 list_for_each_entry(child_bus, &bus->children, node)
81 pcibios_remove_pci_devices(child_bus);
76 82
83 pr_debug("PCI: Removing devices on bus %04x:%02x\n",
84 pci_domain_nr(bus), bus->number);
77 list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { 85 list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
86 pr_debug(" * Removing %s...\n", pci_name(dev));
78 eeh_remove_bus_device(dev); 87 eeh_remove_bus_device(dev);
79 pci_remove_bus_device(dev); 88 pci_remove_bus_device(dev);
80 } 89 }
81} 90}
82EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); 91EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
83 92
84/* Must be called before pci_bus_add_devices */
85void
86pcibios_fixup_new_pci_devices(struct pci_bus *bus)
87{
88 struct pci_dev *dev;
89
90 list_for_each_entry(dev, &bus->devices, bus_list) {
91 /* Skip already-added devices */
92 if (!dev->is_added) {
93 int i;
94
95 /* Fill device archdata and setup iommu table */
96 pcibios_setup_new_device(dev);
97
98 pci_read_irq_line(dev);
99 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
100 struct resource *r = &dev->resource[i];
101
102 if (r->parent || !r->start || !r->flags)
103 continue;
104 pci_claim_resource(dev, i);
105 }
106 }
107 }
108}
109EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices);
110
111static int
112pcibios_pci_config_bridge(struct pci_dev *dev)
113{
114 u8 sec_busno;
115 struct pci_bus *child_bus;
116
117 /* Get busno of downstream bus */
118 pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
119
120 /* Add to children of PCI bridge dev->bus */
121 child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
122 if (!child_bus) {
123 printk (KERN_ERR "%s: could not add second bus\n", __func__);
124 return -EIO;
125 }
126 sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
127
128 pci_scan_child_bus(child_bus);
129
130 /* Fixup new pci devices */
131 pcibios_fixup_new_pci_devices(child_bus);
132
133 /* Make the discovered devices available */
134 pci_bus_add_devices(child_bus);
135
136 eeh_add_device_tree_late(child_bus);
137 return 0;
138}
139
140/** 93/**
141 * pcibios_add_pci_devices - adds new pci devices to bus 94 * pcibios_add_pci_devices - adds new pci devices to bus
142 * 95 *
@@ -147,10 +100,9 @@ pcibios_pci_config_bridge(struct pci_dev *dev)
147 * is how this routine differs from other, similar pcibios 100 * is how this routine differs from other, similar pcibios
148 * routines.) 101 * routines.)
149 */ 102 */
150void 103void pcibios_add_pci_devices(struct pci_bus * bus)
151pcibios_add_pci_devices(struct pci_bus * bus)
152{ 104{
153 int slotno, num, mode; 105 int slotno, num, mode, pass, max;
154 struct pci_dev *dev; 106 struct pci_dev *dev;
155 struct device_node *dn = pci_bus_to_OF_node(bus); 107 struct device_node *dn = pci_bus_to_OF_node(bus);
156 108
@@ -162,26 +114,23 @@ pcibios_add_pci_devices(struct pci_bus * bus)
162 114
163 if (mode == PCI_PROBE_DEVTREE) { 115 if (mode == PCI_PROBE_DEVTREE) {
164 /* use ofdt-based probe */ 116 /* use ofdt-based probe */
165 of_scan_bus(dn, bus); 117 of_rescan_bus(dn, bus);
166 if (!list_empty(&bus->devices)) {
167 pcibios_fixup_new_pci_devices(bus);
168 pci_bus_add_devices(bus);
169 eeh_add_device_tree_late(bus);
170 }
171 } else if (mode == PCI_PROBE_NORMAL) { 118 } else if (mode == PCI_PROBE_NORMAL) {
172 /* use legacy probe */ 119 /* use legacy probe */
173 slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); 120 slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
174 num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); 121 num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
175 if (num) { 122 if (!num)
176 pcibios_fixup_new_pci_devices(bus); 123 return;
177 pci_bus_add_devices(bus); 124 pcibios_setup_bus_devices(bus);
178 eeh_add_device_tree_late(bus); 125 max = bus->secondary;
126 for (pass=0; pass < 2; pass++)
127 list_for_each_entry(dev, &bus->devices, bus_list) {
128 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
129 dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
130 max = pci_scan_bridge(bus, dev, max, pass);
179 } 131 }
180
181 list_for_each_entry(dev, &bus->devices, bus_list)
182 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
183 pcibios_pci_config_bridge(dev);
184 } 132 }
133 pcibios_finish_adding_to_bus(bus);
185} 134}
186EXPORT_SYMBOL_GPL(pcibios_add_pci_devices); 135EXPORT_SYMBOL_GPL(pcibios_add_pci_devices);
187 136
@@ -190,6 +139,8 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
190 struct pci_controller *phb; 139 struct pci_controller *phb;
191 int primary; 140 int primary;
192 141
142 pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name);
143
193 primary = list_empty(&hose_list); 144 primary = list_empty(&hose_list);
194 phb = pcibios_alloc_controller(dn); 145 phb = pcibios_alloc_controller(dn);
195 if (!phb) 146 if (!phb)
@@ -203,11 +154,59 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
203 eeh_add_device_tree_early(dn); 154 eeh_add_device_tree_early(dn);
204 155
205 scan_phb(phb); 156 scan_phb(phb);
206 pcibios_allocate_bus_resources(phb->bus); 157 pcibios_finish_adding_to_bus(phb->bus);
207 pcibios_fixup_new_pci_devices(phb->bus);
208 pci_bus_add_devices(phb->bus);
209 eeh_add_device_tree_late(phb->bus);
210 158
211 return phb; 159 return phb;
212} 160}
213EXPORT_SYMBOL_GPL(init_phb_dynamic); 161EXPORT_SYMBOL_GPL(init_phb_dynamic);
162
163/* RPA-specific bits for removing PHBs */
164int remove_phb_dynamic(struct pci_controller *phb)
165{
166 struct pci_bus *b = phb->bus;
167 struct resource *res;
168 int rc, i;
169
170 pr_debug("PCI: Removing PHB %04x:%02x... \n",
171 pci_domain_nr(b), b->number);
172
173 /* We cannot to remove a root bus that has children */
174 if (!(list_empty(&b->children) && list_empty(&b->devices)))
175 return -EBUSY;
176
177 /* We -know- there aren't any child devices anymore at this stage
178 * and thus, we can safely unmap the IO space as it's not in use
179 */
180 res = &phb->io_resource;
181 if (res->flags & IORESOURCE_IO) {
182 rc = pcibios_unmap_io_space(b);
183 if (rc) {
184 printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
185 __func__, b->name);
186 return 1;
187 }
188 }
189
190 /* Unregister the bridge device from sysfs and remove the PCI bus */
191 device_unregister(b->bridge);
192 phb->bus = NULL;
193 pci_remove_bus(b);
194
195 /* Now release the IO resource */
196 if (res->flags & IORESOURCE_IO)
197 release_resource(res);
198
199 /* Release memory resources */
200 for (i = 0; i < 3; ++i) {
201 res = &phb->mem_resources[i];
202 if (!(res->flags & IORESOURCE_MEM))
203 continue;
204 release_resource(res);
205 }
206
207 /* Free pci_controller data structure */
208 pcibios_free_controller(phb);
209
210 return 0;
211}
212EXPORT_SYMBOL_GPL(remove_phb_dynamic);
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index 9c2a22fed18b..4e3e0382c16e 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -14,6 +14,9 @@
14 * as published by the Free Software Foundation; either version 14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version. 15 * 2 of the License, or (at your option) any later version.
16 */ 16 */
17
18#undef DEBUG
19
17#include <linux/init.h> 20#include <linux/init.h>
18#include <linux/pci.h> 21#include <linux/pci.h>
19#include <linux/string.h> 22#include <linux/string.h>
@@ -151,20 +154,20 @@ static void dlpar_pci_add_bus(struct device_node *dn)
151 return; 154 return;
152 } 155 }
153 156
157 /* Scan below the new bridge */
154 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || 158 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
155 dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) 159 dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
156 of_scan_pci_bridge(dn, dev); 160 of_scan_pci_bridge(dn, dev);
157 161
158 pcibios_fixup_new_pci_devices(dev->subordinate);
159
160 /* Claim new bus resources */
161 pcibios_claim_one_bus(dev->bus);
162
163 /* Map IO space for child bus, which may or may not succeed */ 162 /* Map IO space for child bus, which may or may not succeed */
164 pcibios_map_io_space(dev->subordinate); 163 pcibios_map_io_space(dev->subordinate);
165 164
166 /* Add new devices to global lists. Register in proc, sysfs. */ 165 /* Finish adding it : resource allocation, adding devices, etc...
167 pci_bus_add_devices(phb->bus); 166 * Note that we need to perform the finish pass on the -parent-
167 * bus of the EADS bridge so the bridge device itself gets
168 * properly added
169 */
170 pcibios_finish_adding_to_bus(phb->bus);
168} 171}
169 172
170static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) 173static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
@@ -203,27 +206,6 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
203 return 0; 206 return 0;
204} 207}
205 208
206static int dlpar_remove_root_bus(struct pci_controller *phb)
207{
208 struct pci_bus *phb_bus;
209 int rc;
210
211 phb_bus = phb->bus;
212 if (!(list_empty(&phb_bus->children) &&
213 list_empty(&phb_bus->devices))) {
214 return -EBUSY;
215 }
216
217 rc = pcibios_remove_root_bus(phb);
218 if (rc)
219 return -EIO;
220
221 device_unregister(phb_bus->bridge);
222 pci_remove_bus(phb_bus);
223
224 return 0;
225}
226
227static int dlpar_remove_phb(char *drc_name, struct device_node *dn) 209static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
228{ 210{
229 struct slot *slot; 211 struct slot *slot;
@@ -235,18 +217,15 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
235 217
236 /* If pci slot is hotplugable, use hotplug to remove it */ 218 /* If pci slot is hotplugable, use hotplug to remove it */
237 slot = find_php_slot(dn); 219 slot = find_php_slot(dn);
238 if (slot) { 220 if (slot && rpaphp_deregister_slot(slot)) {
239 if (rpaphp_deregister_slot(slot)) { 221 printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
240 printk(KERN_ERR 222 __func__, drc_name);
241 "%s: unable to remove hotplug slot %s\n", 223 return -EIO;
242 __func__, drc_name);
243 return -EIO;
244 }
245 } 224 }
246 225
247 pdn = dn->data; 226 pdn = dn->data;
248 BUG_ON(!pdn || !pdn->phb); 227 BUG_ON(!pdn || !pdn->phb);
249 rc = dlpar_remove_root_bus(pdn->phb); 228 rc = remove_phb_dynamic(pdn->phb);
250 if (rc < 0) 229 if (rc < 0)
251 return rc; 230 return rc;
252 231
@@ -378,26 +357,38 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
378 if (!bus) 357 if (!bus)
379 return -EINVAL; 358 return -EINVAL;
380 359
381 /* If pci slot is hotplugable, use hotplug to remove it */ 360 pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
361 bus->self ? pci_name(bus->self) : "<!PHB!>");
362
382 slot = find_php_slot(dn); 363 slot = find_php_slot(dn);
383 if (slot) { 364 if (slot) {
365 pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n",
366 pci_domain_nr(bus), bus->number);
367
384 if (rpaphp_deregister_slot(slot)) { 368 if (rpaphp_deregister_slot(slot)) {
385 printk(KERN_ERR 369 printk(KERN_ERR
386 "%s: unable to remove hotplug slot %s\n", 370 "%s: unable to remove hotplug slot %s\n",
387 __func__, drc_name); 371 __func__, drc_name);
388 return -EIO; 372 return -EIO;
389 } 373 }
390 } else 374 }
391 pcibios_remove_pci_devices(bus); 375
376 /* Remove all devices below slot */
377 pcibios_remove_pci_devices(bus);
392 378
379 /* Unmap PCI IO space */
393 if (pcibios_unmap_io_space(bus)) { 380 if (pcibios_unmap_io_space(bus)) {
394 printk(KERN_ERR "%s: failed to unmap bus range\n", 381 printk(KERN_ERR "%s: failed to unmap bus range\n",
395 __func__); 382 __func__);
396 return -ERANGE; 383 return -ERANGE;
397 } 384 }
398 385
386 /* Remove the EADS bridge device itself */
399 BUG_ON(!bus->self); 387 BUG_ON(!bus->self);
388 pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
389 eeh_remove_bus_device(bus->self);
400 pci_remove_bus_device(bus->self); 390 pci_remove_bus_device(bus->self);
391
401 return 0; 392 return 0;
402} 393}
403 394