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);
struct eeh_dev *eeh_addr_cache_get_dev(unsigned long addr);
void eeh_slot_error_detail(struct eeh_pe *pe, int severity);
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);
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);
......
......@@ -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
*
* 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;
int i, state, ret;
/* Determine type of EEH reset required for
* Partitionable Endpoint, a hot-reset (1)
* or a fundamental reset (3).
* A fundamental reset required by any device under
* Partitionable Endpoint trumps hot-reset.
/*
* Determine the type of reset to perform - hot or fundamental.
* Hot reset is the default operation, unless any device under the
* PE requires a fundamental reset.
*/
eeh_pe_dev_traverse(pe, eeh_set_dev_freset, &freset);
if (freset)
eeh_ops->reset(pe, 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;
type = EEH_RESET_FUNDAMENTAL;
/* Mark as reset and block config space */
eeh_pe_state_mark(pe, EEH_PE_RESET | EEH_PE_CFG_BLOCKED);
/* Mark the PE as in reset state and block config space accesses */
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++) {
eeh_reset_pe_once(pe);
ret = eeh_pe_reset(pe, type);
if (ret)
break;
/*
* EEH_PE_ISOLATED is expected to be removed after
* BAR restore.
*/
ret = eeh_pe_reset(pe, EEH_RESET_DEACTIVATE);
if (ret)
break;
/* Wait until the PE is in a functioning state */
state = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
if ((state & flags) == flags) {
ret = 0;
goto out;
}
if ((state & active_flags) == active_flags)
break;
if (state < 0) {
pr_warn("%s: Unrecoverable slot failure on PHB#%x-PE#%x",
__func__, pe->phb->global_number, pe->addr);
ret = -ENOTRECOVERABLE;
goto out;
break;
}
/* We might run out of credits */
/* Set error in case this is our last attempt */
ret = -EIO;
pr_warn("%s: Failure %d resetting PHB#%x-PE#%x\n (%d)\n",
__func__, state, pe->phb->global_number, pe->addr, (i + 1));
}
out:
eeh_pe_state_clear(pe, EEH_PE_RESET | EEH_PE_CFG_BLOCKED);
eeh_pe_state_clear(pe, reset_state);
return ret;
}
......@@ -1601,6 +1592,7 @@ static int eeh_pe_reenable_devices(struct eeh_pe *pe)
return eeh_unfreeze_pe(pe, true);
}
/**
* eeh_pe_reset - Issue PE reset according to specified type
* @pe: EEH 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);
/* Issue reset */
ret = eeh_reset_pe(pe);
ret = eeh_pe_reset_full(pe);
if (ret) {
eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
return ret;
......@@ -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
* PCI config accesses initiated from EEH itself are allowed.
*/
rc = eeh_reset_pe(pe);
rc = eeh_pe_reset_full(pe);
if (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