aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2020-01-21 18:28:38 +1100
committerOliver O'Halloran <oohall@gmail.com>2020-06-03 17:15:50 +1000
commit9b6433c29fddac70eb7b18136b8b130a01c5dc47 (patch)
treea326b570183511a5458b0dadba6883164d6a05cb
parentc42df50e1b19797a69d3a4aeaa496ec7d327b33f (diff)
downloadskiboot-9b6433c29fddac70eb7b18136b8b130a01c5dc47.zip
skiboot-9b6433c29fddac70eb7b18136b8b130a01c5dc47.tar.gz
skiboot-9b6433c29fddac70eb7b18136b8b130a01c5dc47.tar.bz2
hw/phb4: Enable error interrupts
In PHB4 the PHB's error and informational interrupts were changed to behave more like actual LSIs. On PHB3 these interrupts would be only be raised on a 0 -> 1 transition of an error status bits (i.e. they were rising edge triggered). On PHB4 the error interrupts are "true" LSIs and will be re-raised as long the underlying error status bit is set. This causes a headache for us because OPAL's PHB error handling model requires Skiboot to preserve the state of the PHB (including errors) until the kernel is ready to handle the error. As a result we can't do anything in Skiboot to handle the interrupt condition and we need to mask the error internally. We can do this by clearing the relevant bits in the IRQ_ENABLE registers of the PHB. It's worth pointing out that we don't want to mask the interrupt by setting the Q bit in the XIVE ESBs. The ESBs are owned by the OS which may be masking and unmasking the interrupt for its own reasons (e.g. migrating IRQs). Skiboot modifying the ESB state could potentially cause problems and should be avoided. Cc: Cédric Le Goater <clg@kaod.org> Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
-rw-r--r--hw/phb4.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/hw/phb4.c b/hw/phb4.c
index b578ae8..3f22a2c 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -114,7 +114,7 @@
#include <nvram.h>
/* Enable this to disable error interrupts for debug purposes */
-#define DISABLE_ERR_INTS
+#undef DISABLE_ERR_INTS
static void phb4_init_hw(struct phb4 *p);
@@ -3538,6 +3538,33 @@ static void phb4_int_unmask_all(struct phb4 *p)
out_be64(p->regs + PHB_RXE_TCE_ERR_IRQ_ENABLE, 0x60510050c0000000ull);
}
+/*
+ * Mask the IRQ for any currently set error bits. This prevents the PHB's ERR
+ * and INF interrupts from being re-fired before the kernel can handle the
+ * underlying condition.
+ */
+static void phb4_int_mask_active(struct phb4 *p)
+{
+ const uint64_t error_regs[] = {
+ PHB_ERR_STATUS,
+ PHB_TXE_ERR_STATUS,
+ PHB_RXE_ARB_ERR_STATUS,
+ PHB_RXE_MRG_ERR_STATUS,
+ PHB_RXE_TCE_ERR_STATUS
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(error_regs); i++) {
+ uint64_t stat, mask;
+
+ /* The IRQ mask reg is always offset 0x20 from the status reg */
+ stat = phb4_read_reg(p, error_regs[i]);
+ mask = phb4_read_reg(p, error_regs[i] + 0x20);
+
+ phb4_write_reg(p, error_regs[i] + 0x20, mask & ~stat);
+ }
+}
+
static uint64_t phb4_get_pesta(struct phb4 *p, uint64_t pe_number)
{
uint64_t pesta;
@@ -3855,6 +3882,14 @@ static int64_t phb4_eeh_next_error(struct phb *phb,
*severity = OPAL_EEH_SEV_NO_ERROR;
phb4_set_err_pending(p, false);
}
+
+ /*
+ * Unmask all our error interrupts once all pending errors
+ * have been handled.
+ */
+ if (!phb4_err_pending(p))
+ phb4_int_unmask_all(p);
+
return OPAL_SUCCESS;
}
@@ -5593,6 +5628,9 @@ static void phb4_err_interrupt(struct irq_source *is, uint32_t isn)
PHBDBG(p, "Got interrupt 0x%08x\n", isn);
+ /* mask the interrupt conditions to prevent it from re-firing */
+ phb4_int_mask_active(p);
+
/* Update pending event */
opal_update_pending_evt(OPAL_EVENT_PCI_ERROR,
OPAL_EVENT_PCI_ERROR);