Commit 6654c936 authored by Russell Currey's avatar Russell Currey Committed by Michael Ellerman

powerpc/eeh: Refactor EEH PE reset functions

eeh_pe_reset and eeh_reset_pe are two different functions in the same
file which do mostly the same thing.  Not only is this confusing, but
potentially causes disrepancies in functionality, notably eeh_reset_pe
as it does not check return values for failure.

Refactor this into the following:

 - eeh_pe_reset(): stays as is, performs a single operation, exported
 - eeh_pe_reset_full(): new, full reset process that calls eeh_pe_reset()
 - eeh_reset_pe(): removed and replaced by eeh_pe_reset_full()
 - eeh_reset_pe_once(): removed
Signed-off-by: default avatarRussell Currey <ruscur@russell.cc>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 1f52f176
...@@ -53,7 +53,7 @@ void eeh_addr_cache_rmv_dev(struct pci_dev *dev); ...@@ -53,7 +53,7 @@ void eeh_addr_cache_rmv_dev(struct pci_dev *dev);
struct eeh_dev *eeh_addr_cache_get_dev(unsigned long addr); struct eeh_dev *eeh_addr_cache_get_dev(unsigned long addr);
void eeh_slot_error_detail(struct eeh_pe *pe, int severity); void eeh_slot_error_detail(struct eeh_pe *pe, int severity);
int eeh_pci_enable(struct eeh_pe *pe, int function); int eeh_pci_enable(struct eeh_pe *pe, int function);
int eeh_reset_pe(struct eeh_pe *); int eeh_pe_reset_full(struct eeh_pe *pe);
void eeh_save_bars(struct eeh_dev *edev); void eeh_save_bars(struct eeh_dev *edev);
int rtas_write_config(struct pci_dn *, int where, int size, u32 val); int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
......
...@@ -808,76 +808,67 @@ static void *eeh_set_dev_freset(void *data, void *flag) ...@@ -808,76 +808,67 @@ static void *eeh_set_dev_freset(void *data, void *flag)
} }
/** /**
* eeh_reset_pe_once - Assert the pci #RST line for 1/4 second * eeh_pe_reset_full - Complete a full reset process on the indicated PE
* @pe: EEH PE * @pe: EEH PE
* *
* Assert the PCI #RST line for 1/4 second. * This function executes a full reset procedure on a PE, including setting
* the appropriate flags, performing a fundamental or hot reset, and then
* deactivating the reset status. It is designed to be used within the EEH
* subsystem, as opposed to eeh_pe_reset which is exported to drivers and
* only performs a single operation at a time.
*
* This function will attempt to reset a PE three times before failing.
*/ */
static void eeh_reset_pe_once(struct eeh_pe *pe) int eeh_pe_reset_full(struct eeh_pe *pe)
{ {
int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
int reset_state = (EEH_PE_RESET | EEH_PE_CFG_BLOCKED);
int type = EEH_RESET_HOT;
unsigned int freset = 0; unsigned int freset = 0;
int i, state, ret;
/* Determine type of EEH reset required for /*
* Partitionable Endpoint, a hot-reset (1) * Determine the type of reset to perform - hot or fundamental.
* or a fundamental reset (3). * Hot reset is the default operation, unless any device under the
* A fundamental reset required by any device under * PE requires a fundamental reset.
* Partitionable Endpoint trumps hot-reset.
*/ */
eeh_pe_dev_traverse(pe, eeh_set_dev_freset, &freset); eeh_pe_dev_traverse(pe, eeh_set_dev_freset, &freset);
if (freset) if (freset)
eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); type = EEH_RESET_FUNDAMENTAL;
else
eeh_ops->reset(pe, EEH_RESET_HOT);
eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
}
/**
* eeh_reset_pe - Reset the indicated PE
* @pe: EEH PE
*
* This routine should be called to reset indicated device, including
* PE. A PE might include multiple PCI devices and sometimes PCI bridges
* might be involved as well.
*/
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 */ /* Mark the PE as in reset state and block config space accesses */
eeh_pe_state_mark(pe, EEH_PE_RESET | EEH_PE_CFG_BLOCKED); eeh_pe_state_mark(pe, reset_state);
/* Take three shots at resetting the bus */ /* Make three attempts at resetting the bus */
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
eeh_reset_pe_once(pe); ret = eeh_pe_reset(pe, type);
if (ret)
break;
/* ret = eeh_pe_reset(pe, EEH_RESET_DEACTIVATE);
* EEH_PE_ISOLATED is expected to be removed after if (ret)
* BAR restore. break;
*/
/* Wait until the PE is in a functioning state */
state = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); state = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
if ((state & flags) == flags) { if ((state & active_flags) == active_flags)
ret = 0; break;
goto out;
}
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;
goto out; break;
} }
/* We might run out of credits */ /* Set error in case this is our last attempt */
ret = -EIO; ret = -EIO;
pr_warn("%s: Failure %d resetting PHB#%x-PE#%x\n (%d)\n", pr_warn("%s: Failure %d resetting PHB#%x-PE#%x\n (%d)\n",
__func__, state, pe->phb->global_number, pe->addr, (i + 1)); __func__, state, pe->phb->global_number, pe->addr, (i + 1));
} }
out: eeh_pe_state_clear(pe, reset_state);
eeh_pe_state_clear(pe, EEH_PE_RESET | EEH_PE_CFG_BLOCKED);
return ret; return ret;
} }
...@@ -1601,6 +1592,7 @@ static int eeh_pe_reenable_devices(struct eeh_pe *pe) ...@@ -1601,6 +1592,7 @@ static int eeh_pe_reenable_devices(struct eeh_pe *pe)
return eeh_unfreeze_pe(pe, true); return eeh_unfreeze_pe(pe, true);
} }
/** /**
* eeh_pe_reset - Issue PE reset according to specified type * eeh_pe_reset - Issue PE reset according to specified type
* @pe: EEH PE * @pe: EEH PE
......
...@@ -588,7 +588,7 @@ int eeh_pe_reset_and_recover(struct eeh_pe *pe) ...@@ -588,7 +588,7 @@ int eeh_pe_reset_and_recover(struct eeh_pe *pe)
eeh_pe_dev_traverse(pe, eeh_dev_save_state, NULL); eeh_pe_dev_traverse(pe, eeh_dev_save_state, NULL);
/* Issue reset */ /* Issue reset */
ret = eeh_reset_pe(pe); ret = eeh_pe_reset_full(pe);
if (ret) { if (ret) {
eeh_pe_state_clear(pe, EEH_PE_RECOVERING); eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
return ret; return ret;
...@@ -659,7 +659,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus, ...@@ -659,7 +659,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
* config accesses. So we prefer to block them. However, controlled * config accesses. So we prefer to block them. However, controlled
* PCI config accesses initiated from EEH itself are allowed. * PCI config accesses initiated from EEH itself are allowed.
*/ */
rc = eeh_reset_pe(pe); rc = eeh_pe_reset_full(pe);
if (rc) if (rc)
return rc; return rc;
......
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