powerpc/eeh: Report frozen parent PE prior to child PE
When we have the corner case of frozen parent and child PE at the same time, we have to handle the frozen parent PE prior to the child. Without clearning the frozen state on parent PE, the child PE can't be recovered successfully. The patch searches the EEH PE hierarchy tree and returns the toppest frozen PE to be handled. It ensures the frozen parent PE will be handled prior to child PE. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
2c66599206
commit
1ad7a72c5e
|
@ -358,10 +358,11 @@ out:
|
|||
int eeh_dev_check_failure(struct eeh_dev *edev)
|
||||
{
|
||||
int ret;
|
||||
int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
|
||||
unsigned long flags;
|
||||
struct device_node *dn;
|
||||
struct pci_dev *dev;
|
||||
struct eeh_pe *pe;
|
||||
struct eeh_pe *pe, *parent_pe;
|
||||
int rc = 0;
|
||||
const char *location;
|
||||
|
||||
|
@ -439,14 +440,34 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
|
|||
*/
|
||||
if ((ret < 0) ||
|
||||
(ret == EEH_STATE_NOT_SUPPORT) ||
|
||||
(ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) ==
|
||||
(EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) {
|
||||
((ret & active_flags) == active_flags)) {
|
||||
eeh_stats.false_positives++;
|
||||
pe->false_positives++;
|
||||
rc = 0;
|
||||
goto dn_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* It should be corner case that the parent PE has been
|
||||
* put into frozen state as well. We should take care
|
||||
* that at first.
|
||||
*/
|
||||
parent_pe = pe->parent;
|
||||
while (parent_pe) {
|
||||
/* Hit the ceiling ? */
|
||||
if (parent_pe->type & EEH_PE_PHB)
|
||||
break;
|
||||
|
||||
/* Frozen parent PE ? */
|
||||
ret = eeh_ops->get_state(parent_pe, NULL);
|
||||
if (ret > 0 &&
|
||||
(ret & active_flags) != active_flags)
|
||||
pe = parent_pe;
|
||||
|
||||
/* Next parent level */
|
||||
parent_pe = parent_pe->parent;
|
||||
}
|
||||
|
||||
eeh_stats.slot_resets++;
|
||||
|
||||
/* Avoid repeated reports of this failure, including problems
|
||||
|
|
|
@ -705,11 +705,12 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
|
|||
{
|
||||
struct pci_controller *hose;
|
||||
struct pnv_phb *phb;
|
||||
struct eeh_pe *phb_pe;
|
||||
struct eeh_pe *phb_pe, *parent_pe;
|
||||
__be64 frozen_pe_no;
|
||||
__be16 err_type, severity;
|
||||
int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
|
||||
long rc;
|
||||
int ret = EEH_NEXT_ERR_NONE;
|
||||
int state, ret = EEH_NEXT_ERR_NONE;
|
||||
|
||||
/*
|
||||
* While running here, it's safe to purge the event queue.
|
||||
|
@ -838,6 +839,31 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
|
|||
ioda_eeh_phb_diag(hose);
|
||||
}
|
||||
|
||||
/*
|
||||
* We probably have the frozen parent PE out there and
|
||||
* we need have to handle frozen parent PE firstly.
|
||||
*/
|
||||
if (ret == EEH_NEXT_ERR_FROZEN_PE) {
|
||||
parent_pe = (*pe)->parent;
|
||||
while (parent_pe) {
|
||||
/* Hit the ceiling ? */
|
||||
if (parent_pe->type & EEH_PE_PHB)
|
||||
break;
|
||||
|
||||
/* Frozen parent PE ? */
|
||||
state = ioda_eeh_get_state(parent_pe);
|
||||
if (state > 0 &&
|
||||
(state & active_flags) != active_flags)
|
||||
*pe = parent_pe;
|
||||
|
||||
/* Next parent level */
|
||||
parent_pe = parent_pe->parent;
|
||||
}
|
||||
|
||||
/* We possibly migrate to another PE */
|
||||
eeh_pe_state_mark(*pe, EEH_PE_ISOLATED);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have no errors on the specific PHB or only
|
||||
* informative error there, we continue poking it.
|
||||
|
|
Loading…
Reference in New Issue