aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2017-10-23 21:22:22 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-10-23 12:37:52 -0500
commit70eaa3dce5e14d311d93d474b3190509bee4a765 (patch)
treed954ee69b4c5dfe0b762b6156261449913080a3c
parentdc4cdffafee76a19a577276dadd9bf35fe4cbf66 (diff)
downloadskiboot-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.c51
-rw-r--r--include/phb4-regs.h4
2 files changed, 49 insertions, 6 deletions
diff --git a/hw/phb4.c b/hw/phb4.c
index 3b4f014..a537efe 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -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)