mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
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
4 changed files with 44 additions and 11 deletions
|
@ -172,6 +172,7 @@ enum {
|
||||||
#define EEH_OPT_ENABLE 1 /* EEH enable */
|
#define EEH_OPT_ENABLE 1 /* EEH enable */
|
||||||
#define EEH_OPT_THAW_MMIO 2 /* MMIO enable */
|
#define EEH_OPT_THAW_MMIO 2 /* MMIO enable */
|
||||||
#define EEH_OPT_THAW_DMA 3 /* DMA 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_UNAVAILABLE (1 << 0) /* State unavailable */
|
||||||
#define EEH_STATE_NOT_SUPPORT (1 << 1) /* EEH not supported */
|
#define EEH_STATE_NOT_SUPPORT (1 << 1) /* EEH not supported */
|
||||||
#define EEH_STATE_RESET_ACTIVE (1 << 2) /* Active reset */
|
#define EEH_STATE_RESET_ACTIVE (1 << 2) /* Active reset */
|
||||||
|
|
|
@ -1382,6 +1382,13 @@ int eeh_pe_reset(struct eeh_pe *pe, int option)
|
||||||
break;
|
break;
|
||||||
case EEH_RESET_HOT:
|
case EEH_RESET_HOT:
|
||||||
case EEH_RESET_FUNDAMENTAL:
|
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);
|
ret = eeh_ops->reset(pe, option);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -189,6 +189,7 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
|
||||||
{
|
{
|
||||||
struct pci_controller *hose = pe->phb;
|
struct pci_controller *hose = pe->phb;
|
||||||
struct pnv_phb *phb = hose->private_data;
|
struct pnv_phb *phb = hose->private_data;
|
||||||
|
bool freeze_pe = false;
|
||||||
int enable, ret = 0;
|
int enable, ret = 0;
|
||||||
s64 rc;
|
s64 rc;
|
||||||
|
|
||||||
|
@ -212,6 +213,10 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
|
||||||
case EEH_OPT_THAW_DMA:
|
case EEH_OPT_THAW_DMA:
|
||||||
enable = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA;
|
enable = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA;
|
||||||
break;
|
break;
|
||||||
|
case EEH_OPT_FREEZE_PE:
|
||||||
|
freeze_pe = true;
|
||||||
|
enable = OPAL_EEH_ACTION_SET_FREEZE_ALL;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
pr_warn("%s: Invalid option %d\n",
|
pr_warn("%s: Invalid option %d\n",
|
||||||
__func__, option);
|
__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 supports compound PE, to handle it */
|
||||||
if (phb->unfreeze_pe) {
|
if (freeze_pe) {
|
||||||
ret = phb->unfreeze_pe(phb, pe->addr, enable);
|
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 {
|
} else {
|
||||||
rc = opal_pci_eeh_freeze_clear(phb->opal_id,
|
if (phb->unfreeze_pe) {
|
||||||
pe->addr,
|
ret = phb->unfreeze_pe(phb, pe->addr, enable);
|
||||||
enable);
|
} else {
|
||||||
if (rc != OPAL_SUCCESS) {
|
rc = opal_pci_eeh_freeze_clear(phb->opal_id,
|
||||||
pr_warn("%s: Failure %lld enable %d for PHB#%x-PE#%x\n",
|
pe->addr,
|
||||||
__func__, rc, option, phb->hose->global_number,
|
enable);
|
||||||
pe->addr);
|
if (rc != OPAL_SUCCESS) {
|
||||||
ret = -EIO;
|
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)
|
if (pe->addr)
|
||||||
config_addr = pe->addr;
|
config_addr = pe->addr;
|
||||||
break;
|
break;
|
||||||
|
case EEH_OPT_FREEZE_PE:
|
||||||
|
/* Not support */
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
pr_err("%s: Invalid option %d\n",
|
pr_err("%s: Invalid option %d\n",
|
||||||
__func__, option);
|
__func__, option);
|
||||||
|
|
Loading…
Reference in a new issue