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 <gws...@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/eeh.h               |  1 +
 arch/powerpc/kernel/eeh.c                    |  7 +++++
 arch/powerpc/platforms/powernv/eeh-ioda.c    | 43 +++++++++++++++++++++-------
 arch/powerpc/platforms/pseries/eeh_pseries.c |  4 ++-
 4 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index adcddb1..f98b1b5 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -167,6 +167,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         */
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 17cf52ba..898c75f 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -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:
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c 
b/arch/powerpc/platforms/powernv/eeh-ioda.c
index c945bed..f3027b9 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -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;
+                       }
                }
        }
 
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c 
b/arch/powerpc/platforms/pseries/eeh_pseries.c
index b080538..b645dc6 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -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);
-- 
1.8.3.2

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to