aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2012-09-07 18:44:10 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-09-09 19:35:32 -0400
commit82e8882f7f430806bd6bfd203aa4c3f41e3812e9 (patch)
tree6f70cec45cd6d6bf7e39fcf59ed85451a0dfcb17 /arch/powerpc/platforms
parent9b84348c92a122f3ccecda04083ada620312aa53 (diff)
powerpc/eeh: Remove PE at appropriate time
During PCI hotplug and EEH recovery, the PE hierarchy tree might be changed due to the PCI topology changes. At later point when the PCI device is added, the PE will be created dynamically again. The patch introduces new function to remove EEH devices from the associated PE. That also can cause that the parent PE is removed from the PE tree if the parent PE doesn't include valid EEH devices and child PEs. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c1
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pe.c47
2 files changed, 48 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 8f2149061846..b60863b184c3 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1156,6 +1156,7 @@ static void eeh_remove_device(struct pci_dev *dev)
1156 dev->dev.archdata.edev = NULL; 1156 dev->dev.archdata.edev = NULL;
1157 pci_dev_put(dev); 1157 pci_dev_put(dev);
1158 1158
1159 eeh_rmv_from_parent_pe(edev);
1159 pci_addr_cache_remove_device(dev); 1160 pci_addr_cache_remove_device(dev);
1160 eeh_sysfs_remove_device(dev); 1161 eeh_sysfs_remove_device(dev);
1161} 1162}
diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c
index 1d632739d28e..e941e6315fa6 100644
--- a/arch/powerpc/platforms/pseries/eeh_pe.c
+++ b/arch/powerpc/platforms/pseries/eeh_pe.c
@@ -341,3 +341,50 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
341 341
342 return 0; 342 return 0;
343} 343}
344
345/**
346 * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE
347 * @edev: EEH device
348 *
349 * The PE hierarchy tree might be changed when doing PCI hotplug.
350 * Also, the PCI devices or buses could be removed from the system
351 * during EEH recovery. So we have to call the function remove the
352 * corresponding PE accordingly if necessary.
353 */
354int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
355{
356 struct eeh_pe *pe, *parent;
357
358 if (!edev->pe) {
359 pr_warning("%s: No PE found for EEH device %s\n",
360 __func__, edev->dn->full_name);
361 return -EEXIST;
362 }
363
364 /* Remove the EEH device */
365 pe = edev->pe;
366 edev->pe = NULL;
367 list_del(&edev->list);
368
369 /*
370 * Check if the parent PE includes any EEH devices.
371 * If not, we should delete that. Also, we should
372 * delete the parent PE if it doesn't have associated
373 * child PEs and EEH devices.
374 */
375 while (1) {
376 parent = pe->parent;
377 if (pe->type == EEH_PE_PHB)
378 break;
379
380 if (list_empty(&pe->edevs) &&
381 list_empty(&pe->child_list)) {
382 list_del(&pe->child);
383 kfree(pe);
384 }
385
386 pe = parent;
387 }
388
389 return 0;
390}