[Skiboot] [PATCH 08/60] xive: Add support for escalation interrupts

Benjamin Herrenschmidt benh at kernel.crashing.org
Thu Dec 22 14:16:16 AEDT 2016


Escalation interrupts have their "IVE" entry buried inside of
the EQ that shoots them which complicates matters. We want to
expose them to the OS as normal interrupts, so we dedicate a
bit in the interrupt number (outside the range supported by
the OPAL emulation API) to differenciate them. The BlockID and
Index in the interrupt number now refer to the source EQ.

This is still missing proper cache management for them, which
will come in a separate patch.

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
---
 hw/xive.c      | 100 +++++++++++++++++++++++++++++++++++++--------------------
 include/xive.h |   3 ++
 2 files changed, 68 insertions(+), 35 deletions(-)

diff --git a/hw/xive.c b/hw/xive.c
index a8cc2fc..66b9539 100644
--- a/hw/xive.c
+++ b/hw/xive.c
@@ -338,18 +338,23 @@ struct xive {
 /* Conversion between GIRQ and block/index.
  *
  * ------------------------------------
- * |00000000|BLOC|               INDEX|
+ * |0000000E|BLOC|               INDEX|
  * ------------------------------------
  *      8      4           20
  *
- * The global interrupt number is thus limited to 24 bits which is
- * necessary for our XICS emulation since the top 8 bits are
- * reserved for the CPPR value.
+ * the E bit indicates that this is an escalation interrupt, in
+ * that case, the BLOC/INDEX represents the EQ containig the
+ * corresponding escalation descriptor.
+ *
+ * Global interrupt numbers for non-escalation interrupts are thus
+ * limited to 24 bits which is necessary for our XICS emulation since
+ * the top 8 bits are reserved for the CPPR value.
  *
  */
 #define GIRQ_TO_BLK(__g)	(((__g) >> 20) & 0xf)
 #define GIRQ_TO_IDX(__g)	((__g) & 0x000fffff)
 #define BLKIDX_TO_GIRQ(__b,__i)	(((uint32_t)(__b)) << 20 | (__i))
+#define GIRQ_IS_ESCALATION(__g)	((__g) & 0x01000000)
 
 /* VP IDs are just the concatenation of the BLK and index as found
  * in an EQ target field for example
@@ -476,27 +481,6 @@ static struct xive *xive_from_vc_blk(uint32_t blk)
 	return c->xive;
 }
 
-static struct xive_ive *xive_get_ive(struct xive *x, unsigned int isn)
-{
-	struct xive_ive *ivt;
-	uint32_t idx = GIRQ_TO_IDX(isn);
-
-	/* Check the block matches */
-	if (isn < x->int_base || isn >= x->int_max) {
-		xive_err(x, "xive_get_ive, ISN 0x%x not on chip\n", idx);
-		return NULL;
-	}
-	assert (idx < MAX_INT_ENTRIES);
-
-	/* If we support >1 block per chip, this should still work as
-	 * we are likely to make the table contiguous anyway
-	 */
-	ivt = x->ivt_base;
-	assert(ivt);
-
-	return ivt + idx;
-}
-
 static struct xive_eq *xive_get_eq(struct xive *x, unsigned int idx)
 {
 	struct xive_eq *p;
@@ -525,6 +509,45 @@ static struct xive_eq *xive_get_eq(struct xive *x, unsigned int idx)
 #endif
 }
 
+static struct xive_ive *xive_get_ive(struct xive *x, unsigned int isn)
+{
+	struct xive_ive *ivt;
+	uint32_t idx = GIRQ_TO_IDX(isn);
+
+	if (GIRQ_IS_ESCALATION(isn)) {
+		/* Allright, an escalation IVE is buried inside an EQ, let's
+		 * try to find it
+		 */
+		struct xive_eq *eq;
+
+		if (x->chip_id != VC_BLK_TO_CHIP(GIRQ_TO_BLK(isn))) {
+			xive_err(x, "xive_get_ive, ESC ISN 0x%x not on right chip\n", isn);
+			return NULL;
+		}
+		eq = xive_get_eq(x, idx);
+		if (!eq) {
+			xive_err(x, "xive_get_ive, ESC ISN 0x%x EQ not found\n", isn);
+			return NULL;
+		}
+		return (struct xive_ive *)(char *)&eq->w4;
+	} else {
+		/* Check the block matches */
+		if (isn < x->int_base || isn >= x->int_max) {
+			xive_err(x, "xive_get_ive, ISN 0x%x not on right chip\n", isn);
+			return NULL;
+		}
+		assert (idx < MAX_INT_ENTRIES);
+
+		/* If we support >1 block per chip, this should still work as
+		 * we are likely to make the table contiguous anyway
+		 */
+		ivt = x->ivt_base;
+		assert(ivt);
+
+		return ivt + idx;
+	}
+}
+
 static struct xive_vp *xive_get_vp(struct xive *x, unsigned int idx)
 {
 	struct xive_vp *p;
@@ -1295,21 +1318,25 @@ uint32_t xive_alloc_ipi_irqs(uint32_t chip_id, uint32_t count, uint32_t align)
 
 void *xive_get_trigger_port(uint32_t girq)
 {
+	uint32_t idx = GIRQ_TO_IDX(girq);
 	struct xive *x;
-	uint32_t idx;
 
 	/* Find XIVE on which the IVE resides */
 	x = xive_from_isn(girq);
 	if (!x)
 		return NULL;
 
-	/* Make sure it's an IPI on that chip */
-	if (girq < x->int_base ||
-	    girq >= x->int_ipi_top)
-		return NULL;
+	if (GIRQ_IS_ESCALATION(girq)) {
+		/* Page 2 of the EQ MMIO space is the escalate irq */
+		return x->eq_mmio + idx * 0x20000 + 0x10000;
+	} else {
+		/* Make sure it's an IPI on that chip */
+		if (girq < x->int_base ||
+		    girq >= x->int_ipi_top)
+			return NULL;
 
-	idx = girq - x->int_base;
-	return x->esb_mmio + idx * 0x20000;
+		return x->esb_mmio + idx * 0x20000;
+	}
 }
 
 uint64_t xive_get_notify_port(uint32_t chip_id, uint32_t ent)
@@ -1406,6 +1433,7 @@ static bool xive_get_eq_info(uint32_t isn, uint32_t *out_target,
 	uint32_t eq_blk, eq_idx;
 	uint32_t vp_blk, vp_idx;
 	uint32_t prio, server;
+	bool is_escalation = GIRQ_IS_ESCALATION(isn);
 
 	/* Find XIVE on which the IVE resides */
 	x = xive_from_isn(isn);
@@ -1415,7 +1443,7 @@ static bool xive_get_eq_info(uint32_t isn, uint32_t *out_target,
 	ive = xive_get_ive(x, isn);
 	if (!ive)
 		return false;
-	if (!(ive->w & IVE_VALID)) {
+	if (!(ive->w & IVE_VALID) && !is_escalation) {
 		xive_err(x, "ISN %x lead to invalid IVE !\n", isn);
 		return false;
 	}
@@ -1471,6 +1499,7 @@ static bool xive_set_eq_info(uint32_t isn, uint32_t target, uint8_t prio)
 	struct xive *x;
 	struct xive_ive *ive;
 	uint32_t eq_blk, eq_idx;
+	bool is_escalation = GIRQ_IS_ESCALATION(isn);
 
 	/* Find XIVE on which the IVE resides */
 	x = xive_from_isn(isn);
@@ -1480,7 +1509,7 @@ static bool xive_set_eq_info(uint32_t isn, uint32_t target, uint8_t prio)
 	ive = xive_get_ive(x, isn);
 	if (!ive)
 		return false;
-	if (!(ive->w & IVE_VALID)) {
+	if (!(ive->w & IVE_VALID) && !is_escalation) {
 		xive_err(x, "ISN %x lead to invalid IVE !\n", isn);
 		return false;
 	}
@@ -1488,7 +1517,8 @@ static bool xive_set_eq_info(uint32_t isn, uint32_t target, uint8_t prio)
 	/* Are we masking ? */
 	if (prio == 0xff) {
 		/* Masking, just set the M bit */
-		ive->w |= IVE_MASKED;
+		if (!is_escalation)
+			ive->w |= IVE_MASKED;
 
 		xive_vdbg(x, "ISN %x masked !\n", isn);
 	} else {
diff --git a/include/xive.h b/include/xive.h
index 065aa69..e35da6d 100644
--- a/include/xive.h
+++ b/include/xive.h
@@ -276,6 +276,9 @@
  *
  * One per interrupt source. Targets that interrupt to a given EQ
  * and provides the corresponding logical interrupt number (EQ data)
+ *
+ * We also map this structure to the escalation descriptor inside
+ * an EQ, though in that case the valid and masked bits are not used.
  */
 struct xive_ive {
 	/* Use a single 64-bit definition to make it easier to
-- 
2.9.3



More information about the Skiboot mailing list