Commit fef7f905 authored by Sam Bobroff's avatar Sam Bobroff Committed by Michael Ellerman

powerpc/eeh: Cleanup eeh_ops.wait_state()

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: default avatarSam Bobroff <sbobroff@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent e762bb89
...@@ -205,9 +205,8 @@ struct eeh_ops { ...@@ -205,9 +205,8 @@ struct eeh_ops {
void* (*probe)(struct pci_dn *pdn, void *data); void* (*probe)(struct pci_dn *pdn, void *data);
int (*set_option)(struct eeh_pe *pe, int option); int (*set_option)(struct eeh_pe *pe, int option);
int (*get_pe_addr)(struct eeh_pe *pe); 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 (*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 (*get_log)(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len);
int (*configure_bridge)(struct eeh_pe *pe); int (*configure_bridge)(struct eeh_pe *pe);
int (*err_inject)(struct eeh_pe *pe, int type, int func, 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); ...@@ -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); typedef void *(*eeh_pe_traverse_func)(struct eeh_pe *pe, void *flag);
void eeh_set_pe_aux_size(int size); void eeh_set_pe_aux_size(int size);
int eeh_phb_pe_create(struct pci_controller *phb); 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_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_next(struct eeh_pe *pe, struct eeh_pe *root);
struct eeh_pe *eeh_pe_get(struct pci_controller *phb, struct eeh_pe *eeh_pe_get(struct pci_controller *phb,
......
...@@ -681,7 +681,7 @@ int eeh_pci_enable(struct eeh_pe *pe, int function) ...@@ -681,7 +681,7 @@ int eeh_pci_enable(struct eeh_pe *pe, int function)
/* Check if the request is finished successfully */ /* Check if the request is finished successfully */
if (active_flag) { 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) if (rc < 0)
return rc; return rc;
...@@ -920,16 +920,15 @@ int eeh_pe_reset_full(struct eeh_pe *pe) ...@@ -920,16 +920,15 @@ int eeh_pe_reset_full(struct eeh_pe *pe)
break; break;
/* Wait until the PE is in a functioning state */ /* Wait until the PE is in a functioning state */
state = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); state = eeh_wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
if (eeh_state_active(state))
break;
if (state < 0) { if (state < 0) {
pr_warn("%s: Unrecoverable slot failure on PHB#%x-PE#%x", pr_warn("%s: Unrecoverable slot failure on PHB#%x-PE#%x",
__func__, pe->phb->global_number, pe->addr); __func__, pe->phb->global_number, pe->addr);
ret = -ENOTRECOVERABLE; ret = -ENOTRECOVERABLE;
break; break;
} }
if (eeh_state_active(state))
break;
/* Set error in case this is our last attempt */ /* Set error in case this is our last attempt */
ret = -EIO; ret = -EIO;
......
...@@ -836,7 +836,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) ...@@ -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, /* Get the current PCI slot state. This can take a long time,
* sometimes over 300 seconds for certain systems. * 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) { if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) {
pr_warn("EEH: Permanent failure\n"); pr_warn("EEH: Permanent failure\n");
goto hard_fail; goto hard_fail;
......
...@@ -108,6 +108,57 @@ int eeh_phb_pe_create(struct pci_controller *phb) ...@@ -108,6 +108,57 @@ int eeh_phb_pe_create(struct pci_controller *phb)
return 0; 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 * eeh_phb_pe_get - Retrieve PHB PE based on the given PHB
* @phb: PCI controller * @phb: PCI controller
......
...@@ -1133,43 +1133,6 @@ static int pnv_eeh_reset(struct eeh_pe *pe, int option) ...@@ -1133,43 +1133,6 @@ static int pnv_eeh_reset(struct eeh_pe *pe, int option)
return pnv_eeh_bridge_reset(bus->self, 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 * pnv_eeh_get_log - Retrieve error log
* @pe: EEH PE * @pe: EEH PE
...@@ -1688,7 +1651,6 @@ static struct eeh_ops pnv_eeh_ops = { ...@@ -1688,7 +1651,6 @@ static struct eeh_ops pnv_eeh_ops = {
.get_pe_addr = pnv_eeh_get_pe_addr, .get_pe_addr = pnv_eeh_get_pe_addr,
.get_state = pnv_eeh_get_state, .get_state = pnv_eeh_get_state,
.reset = pnv_eeh_reset, .reset = pnv_eeh_reset,
.wait_state = pnv_eeh_wait_state,
.get_log = pnv_eeh_get_log, .get_log = pnv_eeh_get_log,
.configure_bridge = pnv_eeh_configure_bridge, .configure_bridge = pnv_eeh_configure_bridge,
.err_inject = pnv_eeh_err_inject, .err_inject = pnv_eeh_err_inject,
......
...@@ -438,7 +438,7 @@ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe) ...@@ -438,7 +438,7 @@ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe)
/** /**
* pseries_eeh_get_state - Retrieve PE state * pseries_eeh_get_state - Retrieve PE state
* @pe: EEH PE * @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 * Retrieve the state of the specified PE. On RTAS compliant
* pseries platform, there already has one dedicated RTAS function * pseries platform, there already has one dedicated RTAS function
...@@ -448,7 +448,7 @@ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe) ...@@ -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 * 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. * 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 config_addr;
int ret; int ret;
...@@ -499,7 +499,8 @@ static int pseries_eeh_get_state(struct eeh_pe *pe, int *state) ...@@ -499,7 +499,8 @@ static int pseries_eeh_get_state(struct eeh_pe *pe, int *state)
break; break;
case 5: case 5:
if (rets[2]) { if (rets[2]) {
if (state) *state = rets[2]; if (delay)
*delay = rets[2];
result = EEH_STATE_UNAVAILABLE; result = EEH_STATE_UNAVAILABLE;
} else { } else {
result = EEH_STATE_NOT_SUPPORT; result = EEH_STATE_NOT_SUPPORT;
...@@ -553,64 +554,6 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option) ...@@ -553,64 +554,6 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option)
return ret; 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 * pseries_eeh_get_log - Retrieve error log
* @pe: EEH PE * @pe: EEH PE
...@@ -849,7 +792,6 @@ static struct eeh_ops pseries_eeh_ops = { ...@@ -849,7 +792,6 @@ static struct eeh_ops pseries_eeh_ops = {
.get_pe_addr = pseries_eeh_get_pe_addr, .get_pe_addr = pseries_eeh_get_pe_addr,
.get_state = pseries_eeh_get_state, .get_state = pseries_eeh_get_state,
.reset = pseries_eeh_reset, .reset = pseries_eeh_reset,
.wait_state = pseries_eeh_wait_state,
.get_log = pseries_eeh_get_log, .get_log = pseries_eeh_get_log,
.configure_bridge = pseries_eeh_configure_bridge, .configure_bridge = pseries_eeh_configure_bridge,
.err_inject = NULL, .err_inject = NULL,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment