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:
Gavin Shan 2014-09-30 12:38:52 +10:00 committed by Michael Ellerman
parent 940376b3a4
commit 0d5ee5205e
4 changed files with 44 additions and 11 deletions

View File

@ -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 */

View File

@ -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:

View File

@ -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;
}
}
}

View File

@ -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);