powerpc/eeh: Restore initial state in eeh_pe_reset_and_recover()
[deliverable/linux.git] / arch / powerpc / kernel / eeh_driver.c
index fb6207d2c604b4bd9b24d35c57454c080383775a..291fd5137abd4cf2acb43a29725ea42e4bf49ced 100644 (file)
@@ -171,6 +171,16 @@ static void *eeh_dev_save_state(void *data, void *userdata)
        if (!edev)
                return NULL;
 
+       /*
+        * We cannot access the config space on some adapters.
+        * Otherwise, it will cause fenced PHB. We don't save
+        * the content in their config space and will restore
+        * from the initial config space saved when the EEH
+        * device is created.
+        */
+       if (edev->pe && (edev->pe->state & EEH_PE_CFG_RESTRICTED))
+               return NULL;
+
        pdev = eeh_dev_to_pci_dev(edev);
        if (!pdev)
                return NULL;
@@ -312,6 +322,19 @@ static void *eeh_dev_restore_state(void *data, void *userdata)
        if (!edev)
                return NULL;
 
+       /*
+        * The content in the config space isn't saved because
+        * the blocked config space on some adapters. We have
+        * to restore the initial saved config space when the
+        * EEH device is created.
+        */
+       if (edev->pe && (edev->pe->state & EEH_PE_CFG_RESTRICTED)) {
+               if (list_is_last(&edev->list, &edev->pe->edevs))
+                       eeh_pe_restore_bars(edev->pe);
+
+               return NULL;
+       }
+
        pdev = eeh_dev_to_pci_dev(edev);
        if (!pdev)
                return NULL;
@@ -564,9 +587,6 @@ int eeh_pe_reset_and_recover(struct eeh_pe *pe)
        /* Save states */
        eeh_pe_dev_traverse(pe, eeh_dev_save_state, NULL);
 
-       /* Report error */
-       eeh_pe_dev_traverse(pe, eeh_report_error, &result);
-
        /* Issue reset */
        ret = eeh_reset_pe(pe);
        if (ret) {
@@ -621,7 +641,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
         * We don't remove the corresponding PE instances because
         * we need the information afterwords. The attached EEH
         * devices are expected to be attached soon when calling
-        * into pcibios_add_pci_devices().
+        * into pci_hp_add_devices().
         */
        eeh_pe_state_mark(pe, EEH_PE_KEEP);
        if (bus) {
@@ -630,7 +650,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
                } else {
                        eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
                        pci_lock_rescan_remove();
-                       pcibios_remove_pci_devices(bus);
+                       pci_hp_remove_devices(bus);
                        pci_unlock_rescan_remove();
                }
        } else if (frozen_bus) {
@@ -681,7 +701,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
                if (pe->type & EEH_PE_VF)
                        eeh_add_virt_device(edev, NULL);
                else
-                       pcibios_add_pci_devices(bus);
+                       pci_hp_add_devices(bus);
        } else if (frozen_bus && rmv_data->removed) {
                pr_info("EEH: Sleep 5s ahead of partial hotplug\n");
                ssleep(5);
@@ -691,7 +711,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
                if (pe->type & EEH_PE_VF)
                        eeh_add_virt_device(edev, NULL);
                else
-                       pcibios_add_pci_devices(frozen_bus);
+                       pci_hp_add_devices(frozen_bus);
        }
        eeh_pe_state_clear(pe, EEH_PE_KEEP);
 
@@ -896,7 +916,7 @@ perm_error:
                        eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
 
                        pci_lock_rescan_remove();
-                       pcibios_remove_pci_devices(frozen_bus);
+                       pci_hp_remove_devices(frozen_bus);
                        pci_unlock_rescan_remove();
                }
        }
@@ -981,7 +1001,7 @@ static void eeh_handle_special_event(void)
                                bus = eeh_pe_bus_get(phb_pe);
                                eeh_pe_dev_traverse(pe,
                                        eeh_report_failure, NULL);
-                               pcibios_remove_pci_devices(bus);
+                               pci_hp_remove_devices(bus);
                        }
                        pci_unlock_rescan_remove();
                }
This page took 0.02503 seconds and 5 git commands to generate.