[Skiboot] [PATCH 1/3] hw/psi-p9: Mask OPAL-owned LSIs without handlers

Oliver O'Halloran oohall at gmail.com
Fri Aug 30 14:30:23 AEST 2019


Some versions of Swift have the TPM interrupt line of the second chip
pulled up instead of down. This causes the PSI's external (TPM) interrupt
to constantly re-fire since it's an LSI. There's nothing that can be done
to clear the underlying interrupt condition so we need to mask it.

The problem isn't really specific to the external interrupt and will
occur for any of the PSI interrupts that don't have a "real" handler
(FSP, global error, and sometimes the external) so we should mask the
IRQ in OPAL rather than allowing it to re-fire.

If an of the IRQs are directed at Linux then masking them is handled by
Linux.

Cc: Cédric Le Goater <clg at kaod.org>
Signed-off-by: Oliver O'Halloran <oohall at gmail.com>
---
 hw/psi.c | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/hw/psi.c b/hw/psi.c
index a74c105ff0ec..d4b20f1f015f 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -509,6 +509,28 @@ static const struct irq_source_ops psi_p8_irq_ops = {
 	.name = psi_p8_irq_name,
 };
 
+static void psi_p9_mask_unhandled_irq(struct irq_source *is, int isn)
+{
+	struct psi *psi = is->data;
+	uint32_t idx = isn - psi->interrupt;
+	char *name = is->ops->name ? is->ops->name(is, isn) : NULL;
+
+	prerror("PSI: Masking unhandled LSI %d, %s!\n",
+			idx, name ? name : "<unknown>");
+	free(name);
+
+	/*
+	 * All the PSI interrupts are LSIs and will be constantly re-fired
+	 * unless the underlying interrupt condition is cleared. This can
+	 * happen fast enough to hard-lockup a thread so any unhandled IRQs
+	 * need to be masked. We can do that by storing to the 0xD00-0xDFF
+	 * range which sets PQ=01 for that ESB.
+	 *
+	 * NB: The PSI only supports 4K ESB pages
+	 */
+	out_be64(psi->esb_mmio + 0x1000 * idx + 0xD00, 0);
+}
+
 static void psihb_p9_interrupt(struct irq_source *is, uint32_t isn)
 {
 	struct psi *psi = is->data;
@@ -521,21 +543,17 @@ static void psihb_p9_interrupt(struct irq_source *is, uint32_t isn)
 	case P9_PSI_IRQ_OCC:
 		occ_p9_interrupt(psi->chip_id);
 		break;
-	case P9_PSI_IRQ_FSI:
-		printf("PSI: FSI irq received\n");
-		break;
 	case P9_PSI_IRQ_LPCHC:
 		lpc_interrupt(psi->chip_id);
 		break;
 	case P9_PSI_IRQ_LOCAL_ERR:
 		prd_psi_interrupt(psi->chip_id);
 		break;
-	case P9_PSI_IRQ_GLOBAL_ERR:
-		printf("PSI: Global error irq received\n");
-		break;
 	case P9_PSI_IRQ_EXTERNAL:
 		if (platform.external_irq)
 			platform.external_irq(psi->chip_id);
+		else
+			psi_p9_mask_unhandled_irq(is, isn);
 		break;
 	case P9_PSI_IRQ_LPC_SIRQ0:
 	case P9_PSI_IRQ_LPC_SIRQ1:
@@ -553,6 +571,9 @@ static void psihb_p9_interrupt(struct irq_source *is, uint32_t isn)
 	case P9_PSI_IRQ_PSU:
 		p9_sbe_interrupt(psi->chip_id);
 		break;
+
+	default:
+		psi_p9_mask_unhandled_irq(is, isn);
 	}
 }
 
-- 
2.21.0



More information about the Skiboot mailing list