|
@@ -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)
|
|
|
|
|
- * 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);
|
|
eeh_pe_dev_traverse(pe, eeh_set_dev_freset, &freset);
|
|
|
|
|
|
|
|
if (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++) {
|
|
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);
|
|
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) {
|
|
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, EEH_PE_RESET | EEH_PE_CFG_BLOCKED);
|
|
|
|
|
|
|
+ eeh_pe_state_clear(pe, reset_state);
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -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
|