aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/pseries/eeh_pe.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/pseries/eeh_pe.c')
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pe.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c
index 1d632739d28..e941e6315fa 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)
return 0;
}
+
+/**
+ * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE
+ * @edev: EEH device
+ *
+ * The PE hierarchy tree might be changed when doing PCI hotplug.
+ * Also, the PCI devices or buses could be removed from the system
+ * during EEH recovery. So we have to call the function remove the
+ * corresponding PE accordingly if necessary.
+ */
+int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
+{
+ struct eeh_pe *pe, *parent;
+
+ if (!edev->pe) {
+ pr_warning("%s: No PE found for EEH device %s\n",
+ __func__, edev->dn->full_name);
+ return -EEXIST;
+ }
+
+ /* Remove the EEH device */
+ pe = edev->pe;
+ edev->pe = NULL;
+ list_del(&edev->list);
+
+ /*
+ * Check if the parent PE includes any EEH devices.
+ * If not, we should delete that. Also, we should
+ * delete the parent PE if it doesn't have associated
+ * child PEs and EEH devices.
+ */
+ while (1) {
+ parent = pe->parent;
+ if (pe->type == EEH_PE_PHB)
+ break;
+
+ if (list_empty(&pe->edevs) &&
+ list_empty(&pe->child_list)) {
+ list_del(&pe->child);
+ kfree(pe);
+ }
+
+ pe = parent;
+ }
+
+ return 0;
+}