powerpc/eeh: Freeze PE before PE reset
The patch adds one more option (EEH_OPT_FREEZE_PE) to set_option() method to proactively freeze PE, which will be issued before resetting pass-throughed PE to drop MMIO access during reset because it's always contributing to recursive EEH error. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
940376b3a4
commit
0d5ee5205e
@ -172,6 +172,7 @@ enum {
|
||||
#define EEH_OPT_ENABLE 1 /* EEH enable */
|
||||
#define EEH_OPT_THAW_MMIO 2 /* MMIO enable */
|
||||
#define EEH_OPT_THAW_DMA 3 /* DMA enable */
|
||||
#define EEH_OPT_FREEZE_PE 4 /* Freeze PE */
|
||||
#define EEH_STATE_UNAVAILABLE (1 << 0) /* State unavailable */
|
||||
#define EEH_STATE_NOT_SUPPORT (1 << 1) /* EEH not supported */
|
||||
#define EEH_STATE_RESET_ACTIVE (1 << 2) /* Active reset */
|
||||
|
@ -1382,6 +1382,13 @@ int eeh_pe_reset(struct eeh_pe *pe, int option)
|
||||
break;
|
||||
case EEH_RESET_HOT:
|
||||
case EEH_RESET_FUNDAMENTAL:
|
||||
/*
|
||||
* Proactively freeze the PE to drop all MMIO access
|
||||
* during reset, which should be banned as it's always
|
||||
* cause recursive EEH error.
|
||||
*/
|
||||
eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
|
||||
|
||||
ret = eeh_ops->reset(pe, option);
|
||||
break;
|
||||
default:
|
||||
|
@ -189,6 +189,7 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
|
||||
{
|
||||
struct pci_controller *hose = pe->phb;
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
bool freeze_pe = false;
|
||||
int enable, ret = 0;
|
||||
s64 rc;
|
||||
|
||||
@ -212,6 +213,10 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
|
||||
case EEH_OPT_THAW_DMA:
|
||||
enable = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA;
|
||||
break;
|
||||
case EEH_OPT_FREEZE_PE:
|
||||
freeze_pe = true;
|
||||
enable = OPAL_EEH_ACTION_SET_FREEZE_ALL;
|
||||
break;
|
||||
default:
|
||||
pr_warn("%s: Invalid option %d\n",
|
||||
__func__, option);
|
||||
@ -219,17 +224,35 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
|
||||
}
|
||||
|
||||
/* If PHB supports compound PE, to handle it */
|
||||
if (phb->unfreeze_pe) {
|
||||
ret = phb->unfreeze_pe(phb, pe->addr, enable);
|
||||
if (freeze_pe) {
|
||||
if (phb->freeze_pe) {
|
||||
phb->freeze_pe(phb, pe->addr);
|
||||
} else {
|
||||
rc = opal_pci_eeh_freeze_set(phb->opal_id,
|
||||
pe->addr,
|
||||
enable);
|
||||
if (rc != OPAL_SUCCESS) {
|
||||
pr_warn("%s: Failure %lld freezing "
|
||||
"PHB#%x-PE#%x\n",
|
||||
__func__, rc,
|
||||
phb->hose->global_number, pe->addr);
|
||||
ret = -EIO;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = opal_pci_eeh_freeze_clear(phb->opal_id,
|
||||
pe->addr,
|
||||
enable);
|
||||
if (rc != OPAL_SUCCESS) {
|
||||
pr_warn("%s: Failure %lld enable %d for PHB#%x-PE#%x\n",
|
||||
__func__, rc, option, phb->hose->global_number,
|
||||
pe->addr);
|
||||
ret = -EIO;
|
||||
if (phb->unfreeze_pe) {
|
||||
ret = phb->unfreeze_pe(phb, pe->addr, enable);
|
||||
} else {
|
||||
rc = opal_pci_eeh_freeze_clear(phb->opal_id,
|
||||
pe->addr,
|
||||
enable);
|
||||
if (rc != OPAL_SUCCESS) {
|
||||
pr_warn("%s: Failure %lld enable %d "
|
||||
"for PHB#%x-PE#%x\n",
|
||||
__func__, rc, option,
|
||||
phb->hose->global_number, pe->addr);
|
||||
ret = -EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,7 +349,9 @@ static int pseries_eeh_set_option(struct eeh_pe *pe, int option)
|
||||
if (pe->addr)
|
||||
config_addr = pe->addr;
|
||||
break;
|
||||
|
||||
case EEH_OPT_FREEZE_PE:
|
||||
/* Not support */
|
||||
return 0;
|
||||
default:
|
||||
pr_err("%s: Invalid option %d\n",
|
||||
__func__, option);
|
||||
|
Loading…
Reference in New Issue
Block a user