powerpc/eeh: Set EEH_PE_RESET on PE reset
authorGavin Shan <gwshan@linux.vnet.ibm.com>
Thu, 13 Nov 2014 23:47:29 +0000 (10:47 +1100)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 2 Dec 2014 00:03:26 +0000 (11:03 +1100)
The patch introduces additional flag EEH_PE_RESET to indicate the
corresponding PE is under reset. In turn, the PE retrieval bakcend
on PowerNV platform can return unfrozen state for the EEH core to
moving forward. Flag EEH_PE_CFG_BLOCKED isn't the correct one for
the purpose.

In PCI passthrou case, the problem is more worse: Guest doesn't
recover 6th EEH error. The PE is left in isolated (frozen) and
config blocked state on Broadcom adapters. We can't retrieve the
PE's state correctly any more, even from the host side via sysfs
/sys/bus/pci/devices/xxx/eeh_pe_state.

Reported-by: Rajeshkumar Subramanian <rajeshkumars@in.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/eeh.h
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/platforms/powernv/eeh-ioda.c

index ca07f9c27335dd7beb66c9d11e4dba89b30dadc2..2e633b41712ae70a6f0db04f8a49651dd4b39c12 100644 (file)
@@ -72,6 +72,7 @@ struct device_node;
 #define EEH_PE_ISOLATED                (1 << 0)        /* Isolated PE          */
 #define EEH_PE_RECOVERING      (1 << 1)        /* Recovering PE        */
 #define EEH_PE_CFG_BLOCKED     (1 << 2)        /* Block config access  */
+#define EEH_PE_RESET           (1 << 3)        /* PE reset in progress */
 
 #define EEH_PE_KEEP            (1 << 8)        /* Keep PE on hotplug   */
 #define EEH_PE_CFG_RESTRICTED  (1 << 9)        /* Block config on error */
index 967e4a08d824e7886b202e774a179b76e10990c1..b372bfdbfb3acb8361b1946b8f99b1eccf6a3a8e 100644 (file)
@@ -760,6 +760,9 @@ int eeh_reset_pe(struct eeh_pe *pe)
        int flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
        int i, state, ret;
 
+       /* Mark as reset and block config space */
+       eeh_pe_state_mark(pe, EEH_PE_RESET | EEH_PE_CFG_BLOCKED);
+
        /* Take three shots at resetting the bus */
        for (i = 0; i < 3; i++) {
                eeh_reset_pe_once(pe);
@@ -788,6 +791,7 @@ int eeh_reset_pe(struct eeh_pe *pe)
        }
 
 out:
+       eeh_pe_state_clear(pe, EEH_PE_RESET | EEH_PE_CFG_BLOCKED);
        return ret;
 }
 
index 6535936bdf27a38c2e535ae63599af23df8ce414..b17e793ba67ed668bb271d269823e8e88c9e000e 100644 (file)
@@ -528,13 +528,11 @@ int eeh_pe_reset_and_recover(struct eeh_pe *pe)
        eeh_pe_dev_traverse(pe, eeh_report_error, &result);
 
        /* Issue reset */
-       eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
        ret = eeh_reset_pe(pe);
        if (ret) {
-               eeh_pe_state_clear(pe, EEH_PE_RECOVERING | EEH_PE_CFG_BLOCKED);
+               eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
                return ret;
        }
-       eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
 
        /* Unfreeze the PE */
        ret = eeh_clear_pe_frozen_state(pe, true);
@@ -601,19 +599,15 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
         * config accesses. So we prefer to block them. However, controlled
         * PCI config accesses initiated from EEH itself are allowed.
         */
-       eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
        rc = eeh_reset_pe(pe);
-       if (rc) {
-               eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
+       if (rc)
                return rc;
-       }
 
        pci_lock_rescan_remove();
 
        /* Restore PE */
        eeh_ops->configure_bridge(pe);
        eeh_pe_restore_bars(pe);
-       eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
 
        /* Clear frozen state */
        rc = eeh_clear_pe_frozen_state(pe, false);
index db3803e21483ec73d13529add9e9b61032b44f7a..fb38fe4dba89f13c8a3bf2e5b84d1ccfc2d708c7 100644 (file)
@@ -372,7 +372,7 @@ static int ioda_eeh_get_pe_state(struct eeh_pe *pe)
         * moving forward, we have to return operational
         * state during PE reset.
         */
-       if (pe->state & EEH_PE_CFG_BLOCKED) {
+       if (pe->state & EEH_PE_RESET) {
                result = (EEH_STATE_MMIO_ACTIVE  |
                          EEH_STATE_DMA_ACTIVE   |
                          EEH_STATE_MMIO_ENABLED |