powerpc/eeh: Cleanup eeh_ops.wait_state()
authorSam Bobroff <sbobroff@linux.ibm.com>
Wed, 12 Sep 2018 01:23:32 +0000 (11:23 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Sat, 13 Oct 2018 11:21:25 +0000 (22:21 +1100)
The wait_state member of eeh_ops does not need to be platform
dependent; it's just logic around eeh_ops.get_state(). Therefore,
merge the two (slightly different!) platform versions into a new
function, eeh_wait_state() and remove the eeh_ops member.

While doing this, also correct:
* The wait logic, so that it never waits longer than max_wait.
* The wait logic, so that it never waits less than
  EEH_STATE_MIN_WAIT_TIME.
* One call site where the result is treated like a bit field before
  it's checked for negative error values.
* In pseries_eeh_get_state(), rename the "state" parameter to "delay"
  because that's what it is.

Signed-off-by: Sam Bobroff <sbobroff@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/eeh.h
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/eeh_pe.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/pseries/eeh_pseries.c

index 247f09ce44de410f4d2c1e39af9fc87dd03fa6e3..8b596d096ebef7c1ec70c99aed2709b10390034d 100644 (file)
@@ -205,9 +205,8 @@ struct eeh_ops {
        void* (*probe)(struct pci_dn *pdn, void *data);
        int (*set_option)(struct eeh_pe *pe, int option);
        int (*get_pe_addr)(struct eeh_pe *pe);
-       int (*get_state)(struct eeh_pe *pe, int *state);
+       int (*get_state)(struct eeh_pe *pe, int *delay);
        int (*reset)(struct eeh_pe *pe, int option);
-       int (*wait_state)(struct eeh_pe *pe, int max_wait);
        int (*get_log)(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len);
        int (*configure_bridge)(struct eeh_pe *pe);
        int (*err_inject)(struct eeh_pe *pe, int type, int func,
@@ -264,6 +263,7 @@ typedef void *(*eeh_edev_traverse_func)(struct eeh_dev *edev, void *flag);
 typedef void *(*eeh_pe_traverse_func)(struct eeh_pe *pe, void *flag);
 void eeh_set_pe_aux_size(int size);
 int eeh_phb_pe_create(struct pci_controller *phb);
+int eeh_wait_state(struct eeh_pe *pe, int max_wait);
 struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb);
 struct eeh_pe *eeh_pe_next(struct eeh_pe *pe, struct eeh_pe *root);
 struct eeh_pe *eeh_pe_get(struct pci_controller *phb,
index 12e5311d06ed62b924734a141c3669f96ce15c77..6cae6b56ffd66307cfd1e3894868928701114a49 100644 (file)
@@ -681,7 +681,7 @@ int eeh_pci_enable(struct eeh_pe *pe, int function)
 
        /* Check if the request is finished successfully */
        if (active_flag) {
-               rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
+               rc = eeh_wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
                if (rc < 0)
                        return rc;
 
@@ -920,16 +920,15 @@ int eeh_pe_reset_full(struct eeh_pe *pe)
                        break;
 
                /* Wait until the PE is in a functioning state */
-               state = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
-               if (eeh_state_active(state))
-                       break;
-
+               state = eeh_wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
                if (state < 0) {
                        pr_warn("%s: Unrecoverable slot failure on PHB#%x-PE#%x",
                                __func__, pe->phb->global_number, pe->addr);
                        ret = -ENOTRECOVERABLE;
                        break;
                }
+               if (eeh_state_active(state))
+                       break;
 
                /* Set error in case this is our last attempt */
                ret = -EIO;
index c827617613c1ee44c015d5c55ecc2ce328911a0d..e7f757cd839be69ca2dcc4f91dae36390cb34ed5 100644 (file)
@@ -836,7 +836,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
        /* Get the current PCI slot state. This can take a long time,
         * sometimes over 300 seconds for certain systems.
         */
-       rc = eeh_ops->wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000);
+       rc = eeh_wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000);
        if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) {
                pr_warn("EEH: Permanent failure\n");
                goto hard_fail;
index e43dcefbe73f47bf84814e9954fa9cdae4d938a1..6fa2032e05945e1fd5f858e0d37bc3040b0316e7 100644 (file)
@@ -108,6 +108,57 @@ int eeh_phb_pe_create(struct pci_controller *phb)
        return 0;
 }
 
+/**
+ * eeh_wait_state - Wait for PE state
+ * @pe: EEH PE
+ * @max_wait: maximal period in millisecond
+ *
+ * Wait for the state of associated PE. It might take some time
+ * to retrieve the PE's state.
+ */
+int eeh_wait_state(struct eeh_pe *pe, int max_wait)
+{
+       int ret;
+       int mwait;
+
+       /*
+        * According to PAPR, the state of PE might be temporarily
+        * unavailable. Under the circumstance, we have to wait
+        * for indicated time determined by firmware. The maximal
+        * wait time is 5 minutes, which is acquired from the original
+        * EEH implementation. Also, the original implementation
+        * also defined the minimal wait time as 1 second.
+        */
+#define EEH_STATE_MIN_WAIT_TIME        (1000)
+#define EEH_STATE_MAX_WAIT_TIME        (300 * 1000)
+
+       while (1) {
+               ret = eeh_ops->get_state(pe, &mwait);
+
+               if (ret != EEH_STATE_UNAVAILABLE)
+                       return ret;
+
+               if (max_wait <= 0) {
+                       pr_warn("%s: Timeout when getting PE's state (%d)\n",
+                               __func__, max_wait);
+                       return EEH_STATE_NOT_SUPPORT;
+               }
+
+               if (mwait < EEH_STATE_MIN_WAIT_TIME) {
+                       pr_warn("%s: Firmware returned bad wait value %d\n",
+                               __func__, mwait);
+                       mwait = EEH_STATE_MIN_WAIT_TIME;
+               } else if (mwait > EEH_STATE_MAX_WAIT_TIME) {
+                       pr_warn("%s: Firmware returned too long wait value %d\n",
+                               __func__, mwait);
+                       mwait = EEH_STATE_MAX_WAIT_TIME;
+               }
+
+               msleep(min(mwait, max_wait));
+               max_wait -= mwait;
+       }
+}
+
 /**
  * eeh_phb_pe_get - Retrieve PHB PE based on the given PHB
  * @phb: PCI controller
index fd1db9f286f1fafb17cadc99fc86cedf5011c9bc..abc0be7507c8f75d779d47de7e77acbdf2249365 100644 (file)
@@ -1133,43 +1133,6 @@ static int pnv_eeh_reset(struct eeh_pe *pe, int option)
        return pnv_eeh_bridge_reset(bus->self, option);
 }
 
-/**
- * pnv_eeh_wait_state - Wait for PE state
- * @pe: EEH PE
- * @max_wait: maximal period in millisecond
- *
- * Wait for the state of associated PE. It might take some time
- * to retrieve the PE's state.
- */
-static int pnv_eeh_wait_state(struct eeh_pe *pe, int max_wait)
-{
-       int ret;
-       int mwait;
-
-       while (1) {
-               ret = pnv_eeh_get_state(pe, &mwait);
-
-               /*
-                * If the PE's state is temporarily unavailable,
-                * we have to wait for the specified time. Otherwise,
-                * the PE's state will be returned immediately.
-                */
-               if (ret != EEH_STATE_UNAVAILABLE)
-                       return ret;
-
-               if (max_wait <= 0) {
-                       pr_warn("%s: Timeout getting PE#%x's state (%d)\n",
-                               __func__, pe->addr, max_wait);
-                       return EEH_STATE_NOT_SUPPORT;
-               }
-
-               max_wait -= mwait;
-               msleep(mwait);
-       }
-
-       return EEH_STATE_NOT_SUPPORT;
-}
-
 /**
  * pnv_eeh_get_log - Retrieve error log
  * @pe: EEH PE
@@ -1688,7 +1651,6 @@ static struct eeh_ops pnv_eeh_ops = {
        .get_pe_addr            = pnv_eeh_get_pe_addr,
        .get_state              = pnv_eeh_get_state,
        .reset                  = pnv_eeh_reset,
-       .wait_state             = pnv_eeh_wait_state,
        .get_log                = pnv_eeh_get_log,
        .configure_bridge       = pnv_eeh_configure_bridge,
        .err_inject             = pnv_eeh_err_inject,
index 823cb27efa8b88a76f3fdd0d495fb7b6f6f0b0c2..c9e5ca4afb263b56de19af71d095bf794d3f97f0 100644 (file)
@@ -438,7 +438,7 @@ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe)
 /**
  * pseries_eeh_get_state - Retrieve PE state
  * @pe: EEH PE
- * @state: return value
+ * @delay: suggested time to wait if state is unavailable
  *
  * Retrieve the state of the specified PE. On RTAS compliant
  * pseries platform, there already has one dedicated RTAS function
@@ -448,7 +448,7 @@ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe)
  * RTAS calls for the purpose, we need to try the new one and back
  * to the old one if the new one couldn't work properly.
  */
-static int pseries_eeh_get_state(struct eeh_pe *pe, int *state)
+static int pseries_eeh_get_state(struct eeh_pe *pe, int *delay)
 {
        int config_addr;
        int ret;
@@ -499,7 +499,8 @@ static int pseries_eeh_get_state(struct eeh_pe *pe, int *state)
                break;
        case 5:
                if (rets[2]) {
-                       if (state) *state = rets[2];
+                       if (delay)
+                               *delay = rets[2];
                        result = EEH_STATE_UNAVAILABLE;
                } else {
                        result = EEH_STATE_NOT_SUPPORT;
@@ -553,64 +554,6 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option)
        return ret;
 }
 
-/**
- * pseries_eeh_wait_state - Wait for PE state
- * @pe: EEH PE
- * @max_wait: maximal period in millisecond
- *
- * Wait for the state of associated PE. It might take some time
- * to retrieve the PE's state.
- */
-static int pseries_eeh_wait_state(struct eeh_pe *pe, int max_wait)
-{
-       int ret;
-       int mwait;
-
-       /*
-        * According to PAPR, the state of PE might be temporarily
-        * unavailable. Under the circumstance, we have to wait
-        * for indicated time determined by firmware. The maximal
-        * wait time is 5 minutes, which is acquired from the original
-        * EEH implementation. Also, the original implementation
-        * also defined the minimal wait time as 1 second.
-        */
-#define EEH_STATE_MIN_WAIT_TIME        (1000)
-#define EEH_STATE_MAX_WAIT_TIME        (300 * 1000)
-
-       while (1) {
-               ret = pseries_eeh_get_state(pe, &mwait);
-
-               /*
-                * If the PE's state is temporarily unavailable,
-                * we have to wait for the specified time. Otherwise,
-                * the PE's state will be returned immediately.
-                */
-               if (ret != EEH_STATE_UNAVAILABLE)
-                       return ret;
-
-               if (max_wait <= 0) {
-                       pr_warn("%s: Timeout when getting PE's state (%d)\n",
-                               __func__, max_wait);
-                       return EEH_STATE_NOT_SUPPORT;
-               }
-
-               if (mwait <= 0) {
-                       pr_warn("%s: Firmware returned bad wait value %d\n",
-                               __func__, mwait);
-                       mwait = EEH_STATE_MIN_WAIT_TIME;
-               } else if (mwait > EEH_STATE_MAX_WAIT_TIME) {
-                       pr_warn("%s: Firmware returned too long wait value %d\n",
-                               __func__, mwait);
-                       mwait = EEH_STATE_MAX_WAIT_TIME;
-               }
-
-               max_wait -= mwait;
-               msleep(mwait);
-       }
-
-       return EEH_STATE_NOT_SUPPORT;
-}
-
 /**
  * pseries_eeh_get_log - Retrieve error log
  * @pe: EEH PE
@@ -849,7 +792,6 @@ static struct eeh_ops pseries_eeh_ops = {
        .get_pe_addr            = pseries_eeh_get_pe_addr,
        .get_state              = pseries_eeh_get_state,
        .reset                  = pseries_eeh_reset,
-       .wait_state             = pseries_eeh_wait_state,
        .get_log                = pseries_eeh_get_log,
        .configure_bridge       = pseries_eeh_configure_bridge,
        .err_inject             = NULL,