powerpc/eeh: Freeze PE before PE reset
authorGavin Shan <gwshan@linux.vnet.ibm.com>
Tue, 30 Sep 2014 02:38:52 +0000 (12:38 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 30 Sep 2014 07:15:07 +0000 (17:15 +1000)
The patch adds one more option (EEH_OPT_FREEZE_PE) to set_option()
method to proactively freeze PE, which will be issued before resetting
pass-throughed PE to drop MMIO access during reset because it's
always contributing to recursive EEH error.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/eeh.h
arch/powerpc/kernel/eeh.c
arch/powerpc/platforms/powernv/eeh-ioda.c
arch/powerpc/platforms/pseries/eeh_pseries.c

index c79869d4a652d78507e06ae3987701cae8ab0d81..59d3e2a4fc42f8839636dc5a5b5cb151890787ec 100644 (file)
@@ -172,6 +172,7 @@ enum {
 #define EEH_OPT_ENABLE         1       /* EEH enable   */
 #define EEH_OPT_THAW_MMIO      2       /* MMIO enable  */
 #define EEH_OPT_THAW_DMA       3       /* DMA enable   */
+#define EEH_OPT_FREEZE_PE      4       /* Freeze PE    */
 #define EEH_STATE_UNAVAILABLE  (1 << 0)        /* State unavailable    */
 #define EEH_STATE_NOT_SUPPORT  (1 << 1)        /* EEH not supported    */
 #define EEH_STATE_RESET_ACTIVE (1 << 2)        /* Active reset         */
index db35c2722201cd377e332a8a0c8e3291f42d2797..633f6bf965c3094d1af7b9f282339586f6de524f 100644 (file)
@@ -1382,6 +1382,13 @@ int eeh_pe_reset(struct eeh_pe *pe, int option)
                break;
        case EEH_RESET_HOT:
        case EEH_RESET_FUNDAMENTAL:
+               /*
+                * Proactively freeze the PE to drop all MMIO access
+                * during reset, which should be banned as it's always
+                * cause recursive EEH error.
+                */
+               eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
+
                ret = eeh_ops->reset(pe, option);
                break;
        default:
index df5c2cc552850685119f9d68c9aab03d4323c97a..1d8f37b93457d40d14707c087db237f6c8753340 100644 (file)
@@ -189,6 +189,7 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
 {
        struct pci_controller *hose = pe->phb;
        struct pnv_phb *phb = hose->private_data;
+       bool freeze_pe = false;
        int enable, ret = 0;
        s64 rc;
 
@@ -212,6 +213,10 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
        case EEH_OPT_THAW_DMA:
                enable = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA;
                break;
+       case EEH_OPT_FREEZE_PE:
+               freeze_pe = true;
+               enable = OPAL_EEH_ACTION_SET_FREEZE_ALL;
+               break;
        default:
                pr_warn("%s: Invalid option %d\n",
                        __func__, option);
@@ -219,17 +224,35 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
        }
 
        /* If PHB supports compound PE, to handle it */
-       if (phb->unfreeze_pe) {
-               ret = phb->unfreeze_pe(phb, pe->addr, enable);
+       if (freeze_pe) {
+               if (phb->freeze_pe) {
+                       phb->freeze_pe(phb, pe->addr);
+               } else {
+                       rc = opal_pci_eeh_freeze_set(phb->opal_id,
+                                                    pe->addr,
+                                                    enable);
+                       if (rc != OPAL_SUCCESS) {
+                               pr_warn("%s: Failure %lld freezing "
+                                       "PHB#%x-PE#%x\n",
+                                       __func__, rc,
+                                       phb->hose->global_number, pe->addr);
+                               ret = -EIO;
+                       }
+               }
        } else {
-               rc = opal_pci_eeh_freeze_clear(phb->opal_id,
-                                              pe->addr,
-                                              enable);
-               if (rc != OPAL_SUCCESS) {
-                       pr_warn("%s: Failure %lld enable %d for PHB#%x-PE#%x\n",
-                               __func__, rc, option, phb->hose->global_number,
-                               pe->addr);
-                       ret = -EIO;
+               if (phb->unfreeze_pe) {
+                       ret = phb->unfreeze_pe(phb, pe->addr, enable);
+               } else {
+                       rc = opal_pci_eeh_freeze_clear(phb->opal_id,
+                                                      pe->addr,
+                                                      enable);
+                       if (rc != OPAL_SUCCESS) {
+                               pr_warn("%s: Failure %lld enable %d "
+                                       "for PHB#%x-PE#%x\n",
+                                       __func__, rc, option,
+                                       phb->hose->global_number, pe->addr);
+                               ret = -EIO;
+                       }
                }
        }
 
index b08053819d99f1f9d2a7da36828faa268837e66e..b645dc60e0004637c9046bad341f2681e2d8d234 100644 (file)
@@ -349,7 +349,9 @@ static int pseries_eeh_set_option(struct eeh_pe *pe, int option)
                if (pe->addr)
                        config_addr = pe->addr;
                break;
-
+       case EEH_OPT_FREEZE_PE:
+               /* Not support */
+               return 0;
        default:
                pr_err("%s: Invalid option %d\n",
                        __func__, option);