[Skiboot] [PATCH V3 08/15] pau: enable interrupt on error

Christophe Lombard clombard at linux.vnet.ibm.com
Fri Oct 15 02:56:57 AEDT 2021


The default action for the errors (unexpected errors on the opencapi
link) reported in the PAU FIR2 registe is mostly set to system
checkstop.

This patch changes the default action of those errors so that the PAU
will raise an interrupt instead. Interrupt information are logged so
that the error can be debugged and linux can catch the event.

Signed-off-by: Christophe Lombard <clombard at linux.vnet.ibm.com>

Reviewed-by: Frederic Barrat <fbarrat at linux.ibm.com>
---
 hw/pau.c           | 157 +++++++++++++++++++++++++++++++++++++++++++++
 include/pau-regs.h |  12 ++++
 include/pau.h      |   2 +
 3 files changed, 171 insertions(+)

diff --git a/hw/pau.c b/hw/pau.c
index 36c5f224..eb317151 100644
--- a/hw/pau.c
+++ b/hw/pau.c
@@ -5,6 +5,7 @@
 #include <interrupts.h>
 #include <pci-slot.h>
 #include <phys-map.h>
+#include <xive.h>
 #include <pau.h>
 #include <pau-regs.h>
 #include <xscom-p10-regs.h>
@@ -237,6 +238,15 @@ static int pau_opencapi_set_fence_control(struct pau_dev *dev,
 	return OPAL_HARDWARE;
 }
 
+#define PAU_DEV_STATUS_BROKEN	0x1
+
+static void pau_opencapi_set_broken(struct pau_dev *dev)
+{
+	PAUDEVDBG(dev, "Update status to broken\n");
+
+	dev->status = PAU_DEV_STATUS_BROKEN;
+}
+
 static void pau_opencapi_mask_firs(struct pau *pau)
 {
 	uint64_t reg, val;
@@ -310,6 +320,113 @@ static void pau_opencapi_assign_bars(struct pau *pau)
 	}
 }
 
+static uint64_t pau_opencapi_ipi_attributes(struct irq_source *is,
+					    uint32_t isn)
+{
+	struct pau *pau = is->data;
+	uint32_t level = isn - pau->irq_base;
+
+	if (level >= 37 && level <= 40) {
+		/* level 37-40: OTL/XSL interrupt */
+		return IRQ_ATTR_TARGET_OPAL |
+		       IRQ_ATTR_TARGET_RARE |
+		       IRQ_ATTR_TYPE_MSI;
+	}
+
+	return IRQ_ATTR_TARGET_LINUX;
+}
+
+static void pau_opencapi_ipi_interrupt(struct irq_source *is,
+				       uint32_t isn)
+{
+	struct pau *pau = is->data;
+	uint32_t level = isn - pau->irq_base;
+	struct pau_dev *dev;
+
+	switch (level) {
+	case 37 ... 40:
+		pau_for_each_opencapi_dev(dev, pau)
+			pau_opencapi_set_broken(dev);
+
+		opal_update_pending_evt(OPAL_EVENT_PCI_ERROR,
+					OPAL_EVENT_PCI_ERROR);
+		break;
+	default:
+		PAUERR(pau, "Received unknown interrupt %d\n", level);
+		return;
+	}
+}
+
+#define PAU_IRQ_LEVELS 60
+
+static char *pau_opencapi_ipi_name(struct irq_source *is, uint32_t isn)
+{
+	struct pau *pau = is->data;
+	uint32_t level = isn - pau->irq_base;
+
+	switch (level) {
+	case 0 ... 19:
+		return strdup("Reserved");
+	case 20:
+		return strdup("An error event related to PAU CQ functions");
+	case 21:
+		return strdup("An error event related to PAU MISC functions");
+	case 22 ... 34:
+		return strdup("Reserved");
+	case 35:
+		return strdup("Translation failure for OCAPI link 0");
+	case 36:
+		return strdup("Translation failure for OCAPI link 1");
+	case 37:
+		return strdup("An error event related to OTL for link 0");
+	case 38:
+		return strdup("An error event related to OTL for link 1");
+	case 39:
+		return strdup("An error event related to XSL for link 0");
+	case 40:
+		return strdup("An error event related to XSL for link 1");
+	case 41 ... 59:
+		return strdup("Reserved");
+	}
+
+	return strdup("Unknown");
+}
+
+static const struct irq_source_ops pau_opencapi_ipi_ops = {
+	.attributes	= pau_opencapi_ipi_attributes,
+	.interrupt	= pau_opencapi_ipi_interrupt,
+	.name		= pau_opencapi_ipi_name,
+};
+
+static void pau_opencapi_setup_irqs(struct pau *pau)
+{
+	uint64_t reg, val;
+	uint32_t base;
+
+	base = xive2_alloc_ipi_irqs(pau->chip_id, PAU_IRQ_LEVELS, 64);
+	if (base == XIVE_IRQ_ERROR) {
+		PAUERR(pau, "Failed to allocate interrupt sources\n");
+		return;
+	}
+
+	xive2_register_ipi_source(base, PAU_IRQ_LEVELS, pau, &pau_opencapi_ipi_ops);
+
+	/* Set IPI configuration */
+	reg = PAU_MISC_CONFIG;
+	val = pau_read(pau, reg);
+	val = SETFIELD(PAU_MISC_CONFIG_IPI_PS, val, PAU_MISC_CONFIG_IPI_PS_64K);
+	val = SETFIELD(PAU_MISC_CONFIG_IPI_OS, val, PAU_MISC_CONFIG_IPI_OS_AIX);
+	pau_write(pau, reg, val);
+
+	/* Set IRQ base */
+	reg = PAU_MISC_INT_BAR;
+	val = SETFIELD(PAU_MISC_INT_BAR_ADDR, 0ull,
+		       (uint64_t)xive2_get_trigger_port(base) >> 12);
+	pau_write(pau, reg, val);
+
+	pau->irq_base = base;
+}
+
 static void pau_opencapi_enable_bars(struct pau_dev *dev, bool enable)
 {
 	struct pau *pau = dev->pau;
@@ -769,6 +886,41 @@ static void pau_opencapi_address_translation_config(struct pau_dev *dev)
 	/* XSL_GP  - use defaults */
 }
 
+static void pau_opencapi_enable_interrupt_on_error(struct pau_dev *dev)
+{
+	struct pau *pau = dev->pau;
+	uint64_t reg, val;
+
+	PAUDEVDBG(dev, "Enable Interrupt-on-error\n");
+
+	/* translation fault */
+	reg = PAU_MISC_INT_2_CONFIG;
+	val = pau_read(pau, reg);
+	val |= PAU_MISC_INT_2_CONFIG_XFAULT_2_5(dev->index);
+	pau_write(pau, reg, val);
+
+	/* freeze disable */
+	reg = PAU_MISC_FREEZE_1_CONFIG;
+	val = pau_read(pau, reg);
+	val &= ~PAU_FIR1_NDL_BRICKS_0_5;
+	val &= ~PAU_FIR1_NDL_BRICKS_6_11;
+	pau_write(pau, reg, val);
+
+	/* fence disable */
+	reg = PAU_MISC_FENCE_1_CONFIG;
+	val = pau_read(pau, reg);
+	val &= ~PAU_FIR1_NDL_BRICKS_0_5;
+	val &= ~PAU_FIR1_NDL_BRICKS_6_11;
+	pau_write(pau, reg, val);
+
+	/* irq disable */
+	reg = PAU_MISC_INT_1_CONFIG;
+	val = pau_read(pau, reg);
+	val &= ~PAU_FIR1_NDL_BRICKS_0_5;
+	val &= ~PAU_FIR1_NDL_BRICKS_6_11;
+	pau_write(pau, reg, val);
+}
+
 static void pau_opencapi_enable_ref_clock(struct pau_dev *dev)
 {
 	uint64_t reg, val;
@@ -817,6 +969,7 @@ static void pau_opencapi_init_hw(struct pau *pau)
 
 	pau_opencapi_mask_firs(pau);
 	pau_opencapi_assign_bars(pau);
+	pau_opencapi_setup_irqs(pau);
 
 	/* Create phb */
 	pau_for_each_opencapi_dev(dev, pau) {
@@ -893,6 +1046,10 @@ static void pau_opencapi_init_hw(struct pau *pau)
 		 * AFU's memory
 		 */
 
+		/* Procedure 17.1.3.11 - Interrupt Configuration */
+		/* done in pau_opencapi_setup_irqs() */
+		pau_opencapi_enable_interrupt_on_error(dev);
+
 		/* Reset disabled. Place OTLs into Run State */
 		pau_opencapi_set_fence_control(dev, 0b00);
 
diff --git a/include/pau-regs.h b/include/pau-regs.h
index e4ff7cc0..d98f435b 100644
--- a/include/pau-regs.h
+++ b/include/pau-regs.h
@@ -139,6 +139,18 @@
 #define PAU_MISC_HOLD				(PAU_BLOCK_PAU_MISC + 0x020)
 #define   PAU_MISC_HOLD_NDL_STALL		PPC_BITMASK(0, 3)
 #define PAU_MISC_CONFIG				(PAU_BLOCK_PAU_MISC + 0x030)
+#define   PAU_MISC_CONFIG_IPI_PS		PPC_BIT(11)
+#define   PAU_MISC_CONFIG_IPI_PS_64K		1
+#define   PAU_MISC_CONFIG_IPI_OS		PPC_BIT(12)
+#define   PAU_MISC_CONFIG_IPI_OS_AIX		0
 #define   PAU_MISC_CONFIG_OC_MODE		PPC_BIT(16)
+#define PAU_MISC_FREEZE_1_CONFIG		(PAU_BLOCK_PAU_MISC + 0x048)
+#define PAU_MISC_FENCE_1_CONFIG			(PAU_BLOCK_PAU_MISC + 0x058)
+#define PAU_MISC_INT_1_CONFIG			(PAU_BLOCK_PAU_MISC + 0x068)
+#define PAU_MISC_INT_BAR			(PAU_BLOCK_PAU_MISC + 0x098)
+#define   PAU_MISC_INT_BAR_ADDR			PPC_BITMASK(0, 39)
+#define PAU_MISC_INT_2_CONFIG			(PAU_BLOCK_PAU_MISC + 0x408)
+#define   PAU_MISC_INT_2_CONFIG_XFAULT_2_5(n)	PPC_BIT(0 + (n))
+#define   PAU_MISC_INT_2_CONFIG_XFAULT_0_1(n)	PPC_BIT(54 + (n))
 
 #endif /* __PAU_REGS_H */
diff --git a/include/pau.h b/include/pau.h
index 0246a63d..b6fabe7f 100644
--- a/include/pau.h
+++ b/include/pau.h
@@ -33,6 +33,7 @@ struct pau_dev {
 	uint32_t		index;
 	struct dt_node		*dn;
 	struct phb		phb;
+	uint32_t		status;
 
 	struct pau_bar		ntl_bar;
 	struct pau_bar		genid_bar;
@@ -59,6 +60,7 @@ struct pau {
 	uint64_t		regs[2];
 	bool			mmio_access;
 
+	uint32_t		irq_base;
 	struct lock		lock;
 
 	uint32_t		links;
-- 
2.31.1



More information about the Skiboot mailing list