diff options
author | Michael Neuling <mikey@neuling.org> | 2017-10-23 21:22:22 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2017-10-23 12:37:52 -0500 |
commit | 70eaa3dce5e14d311d93d474b3190509bee4a765 (patch) | |
tree | d954ee69b4c5dfe0b762b6156261449913080a3c | |
parent | dc4cdffafee76a19a577276dadd9bf35fe4cbf66 (diff) | |
download | skiboot-70eaa3dce5e14d311d93d474b3190509bee4a765.zip skiboot-70eaa3dce5e14d311d93d474b3190509bee4a765.tar.gz skiboot-70eaa3dce5e14d311d93d474b3190509bee4a765.tar.bz2 |
phb4: Escalate freeze to fence to avoid checkstop
Freeze events such as MMIO loads can cause the PHB to lose it's
limited powerbus credits. If all credits are used and a further MMIO
will cause a checkstop.
To work around this, we escalate the troublesome freeze events to a
fence. The fence will cause a full PHB reset which resets the powerbus
credits and avoids the checkstop.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r-- | hw/phb4.c | 51 | ||||
-rw-r--r-- | include/phb4-regs.h | 4 |
2 files changed, 49 insertions, 6 deletions
@@ -2973,6 +2973,29 @@ static struct pci_slot *phb4_slot_create(struct phb *phb) return slot; } +static uint64_t phb4_get_pesta(struct phb4 *p, uint64_t pe_number) +{ + uint64_t pesta, *pPEST; + + pPEST = (uint64_t *)p->tbl_pest; + + phb4_ioda_sel(p, IODA3_TBL_PESTA, pe_number, false); + pesta = phb4_read_reg(p, PHB_IODA_DATA0); + if (pesta & IODA3_PESTA_MMIO_FROZEN) + pesta |= pPEST[2*pe_number]; + + return pesta; +} + +static bool phb4_freeze_escalate(uint64_t pesta) +{ + if ((GETFIELD(IODA3_PESTA_TRANS_TYPE, pesta) == + IODA3_PESTA_TRANS_TYPE_MMIOLOAD) && + (pesta & (IODA3_PESTA_CA_CMPLT_TMT | IODA3_PESTA_UR))) + return true; + return false; +} + static int64_t phb4_eeh_freeze_status(struct phb *phb, uint64_t pe_number, uint8_t *freeze_state, uint16_t *pci_error_type, @@ -3016,13 +3039,21 @@ static int64_t phb4_eeh_freeze_status(struct phb *phb, uint64_t pe_number, if (severity) *severity = OPAL_EEH_SEV_PE_ER; - /* Read the PESTA & PESTB */ - phb4_ioda_sel(p, IODA3_TBL_PESTA, pe_number, false); - pesta = in_be64(p->regs + PHB_IODA_DATA0); + /* Read the full PESTA */ + pesta = phb4_get_pesta(p, pe_number); + /* Check if we need to escalate to fence */ + if (phb4_freeze_escalate(pesta)) { + PHBERR(p, "Escalating freeze to fence PESTA[%lli]=%016llx\n", + pe_number, pesta); + *severity = OPAL_EEH_SEV_PHB_FENCED; + *pci_error_type = OPAL_EEH_PHB_ERROR; + } + + /* Read the PESTB in the PHB */ phb4_ioda_sel(p, IODA3_TBL_PESTB, pe_number, false); - pestb = in_be64(p->regs + PHB_IODA_DATA0); + pestb = phb4_read_reg(p, PHB_IODA_DATA0); - /* Convert them */ + /* Convert PESTA/B to freeze_state */ if (pesta & IODA3_PESTA_MMIO_FROZEN) *freeze_state |= OPAL_EEH_STOPPED_MMIO_FREEZE; if (pestb & IODA3_PESTB_DMA_STOPPED) @@ -3134,7 +3165,7 @@ static int64_t phb4_eeh_next_error(struct phb *phb, uint16_t *severity) { struct phb4 *p = phb_to_phb4(phb); - uint64_t peev; + uint64_t peev, pesta; uint32_t peev_size = p->num_pes/64; int32_t i, j; @@ -3201,7 +3232,15 @@ static int64_t phb4_eeh_next_error(struct phb *phb, if (*first_frozen_pe != (uint64_t)(-1)) break; } + } + if (*first_frozen_pe != (uint64_t)(-1)) { + pesta = phb4_get_pesta(p, *first_frozen_pe); + if (phb4_freeze_escalate(pesta)) { + PHBINF(p, "Escalating freeze to fence. PESTA[%lli]=%016llx\n", + *first_frozen_pe, pesta); + p->err.err_class = PHB4_ERR_CLASS_FENCED; + } } switch (p->err.err_class) { diff --git a/include/phb4-regs.h b/include/phb4-regs.h index e83c8c3..0d8aa48 100644 --- a/include/phb4-regs.h +++ b/include/phb4-regs.h @@ -435,6 +435,10 @@ /* PESTA */ #define IODA3_PESTA_MMIO_FROZEN PPC_BIT(0) +#define IODA3_PESTA_TRANS_TYPE PPC_BITMASK(5,7) +#define IODA3_PESTA_TRANS_TYPE_MMIOLOAD 0x4 +#define IODA3_PESTA_CA_CMPLT_TMT PPC_BIT(8) +#define IODA3_PESTA_UR PPC_BIT(9) /* PESTB */ #define IODA3_PESTB_DMA_STOPPED PPC_BIT(0) |