* in the corresponding PHB. Therefore, the root PEs should be created
  * against existing PHBs in on-to-one fashion.
  */
-#define EEH_PE_PHB     1       /* PHB PE    */
-#define EEH_PE_DEVICE  2       /* Device PE */
-#define EEH_PE_BUS     3       /* Bus PE    */
+#define EEH_PE_INVALID (1 << 0)        /* Invalid   */
+#define EEH_PE_PHB     (1 << 1)        /* PHB PE    */
+#define EEH_PE_DEVICE  (1 << 2)        /* Device PE */
+#define EEH_PE_BUS     (1 << 3)        /* Bus PE    */
 
 #define EEH_PE_ISOLATED                (1 << 0)        /* Isolated PE          */
 #define EEH_PE_RECOVERING      (1 << 1)        /* Recovering PE        */
 
                 * the PE for PHB has been determined when that
                 * was created.
                 */
-               if (pe->type == EEH_PE_PHB &&
+               if ((pe->type & EEH_PE_PHB) &&
                    pe->phb == phb) {
                        eeh_unlock();
                        return pe;
        struct eeh_dev *edev = (struct eeh_dev *)flag;
 
        /* Unexpected PHB PE */
-       if (pe->type == EEH_PE_PHB)
+       if (pe->type & EEH_PE_PHB)
                return NULL;
 
        /* We prefer PE address */
         * components.
         */
        pe = eeh_pe_get(edev);
-       if (pe) {
+       if (pe && !(pe->type & EEH_PE_INVALID)) {
                if (!edev->pe_config_addr) {
                        pr_err("%s: PE with addr 0x%x already exists\n",
                                __func__, edev->config_addr);
                pr_debug("EEH: Add %s to Bus PE#%x\n",
                        edev->dn->full_name, pe->addr);
 
+               return 0;
+       } else if (pe && (pe->type & EEH_PE_INVALID)) {
+               list_add_tail(&edev->list, &pe->edevs);
+               edev->pe = pe;
+               /*
+                * We're running to here because of PCI hotplug caused by
+                * EEH recovery. We need clear EEH_PE_INVALID until the top.
+                */
+               parent = pe;
+               while (parent) {
+                       if (!(parent->type & EEH_PE_INVALID))
+                               break;
+                       parent->type &= ~EEH_PE_INVALID;
+                       parent = parent->parent;
+               }
+               pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
+                       edev->dn->full_name, pe->addr, pe->parent->addr);
+
                return 0;
        }
 
  */
 int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
 {
-       struct eeh_pe *pe, *parent;
+       struct eeh_pe *pe, *parent, *child;
+       int cnt;
 
        if (!edev->pe) {
                pr_warning("%s: No PE found for EEH device %s\n",
         */
        while (1) {
                parent = pe->parent;
-               if (pe->type == EEH_PE_PHB)
+               if (pe->type & EEH_PE_PHB)
                        break;
 
-               if (list_empty(&pe->edevs) &&
-                   list_empty(&pe->child_list)) {
-                       list_del(&pe->child);
-                       kfree(pe);
+               if (list_empty(&pe->edevs)) {
+                       cnt = 0;
+                       list_for_each_entry(child, &pe->child_list, child) {
+                               if (!(pe->type & EEH_PE_INVALID)) {
+                                       cnt++;
+                                       break;
+                               }
+                       }
+
+                       if (!cnt)
+                               pe->type |= EEH_PE_INVALID;
+                       else
+                               break;
                }
 
                pe = parent;
        struct eeh_dev *edev;
        struct pci_dev *pdev;
 
-       if (pe->type == EEH_PE_PHB) {
+       if (pe->type & EEH_PE_PHB) {
                bus = pe->phb->bus;
-       } else if (pe->type == EEH_PE_BUS) {
+       } else if (pe->type & EEH_PE_BUS) {
                edev = list_first_entry(&pe->edevs, struct eeh_dev, list);
                pdev = eeh_dev_to_pci_dev(edev);
                if (pdev)