[Skiboot] [PATCH] xive+phb4: Fix exposing trigger page to Linux

Benjamin Herrenschmidt benh at kernel.crashing.org
Thu Apr 27 23:56:39 AEST 2017


We currently don't expose the trigger page of MSIs to Linux which
breaks re-sending of a queued one. To fix that properly we need
to understand out a subtle API complication:

 - The "internal" XIVE_SRC_TRIGGER_PAGE indicates that a trigger
page is supported, whether it's the same page as the EOI page
or not.

 - The "external" OPAL_XIVE_IRQ_TRIGGER_PAGE indicates that a
*separate* trigger page exists. To know if triggers are supported
the caller should simply check if a valid (non-0) value is returned
in "out_trig_page" of opal_xive_get_irq_info().

So PHB4 must set XIVE_SRC_TRIGGER_PAGE for MSIs and the xive code
needs to do the "right" thing for setting whether
OPAL_XIVE_IRQ_TRIGGER_PAGE should be set or not.

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
---
 hw/phb4.c      |  3 ++-
 hw/xive.c      | 15 ++++++++++++---
 include/xive.h | 14 +++++++++-----
 3 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/hw/phb4.c b/hw/phb4.c
index 12e17bd..e1f0bcb 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -3383,7 +3383,8 @@ static void phb4_create(struct dt_node *np)
 
 	/* Register all interrupt sources with XIVE */
 	xive_register_hw_source(p->base_msi, p->num_irqs - 8, 16,
-				p->int_mmio, XIVE_SRC_SHIFT_BUG,
+				p->int_mmio,
+				XIVE_SRC_SHIFT_BUG | XIVE_SRC_TRIGGER_PAGE,
 				NULL, NULL);
 
 	xive_register_hw_source(p->base_lsi, 8, 16,
diff --git a/hw/xive.c b/hw/xive.c
index ed1dc90..1952ce6 100644
--- a/hw/xive.c
+++ b/hw/xive.c
@@ -3372,8 +3372,14 @@ static uint64_t xive_convert_irq_flags(uint64_t iflags)
 
 	if (iflags & XIVE_SRC_STORE_EOI)
 		oflags |= OPAL_XIVE_IRQ_STORE_EOI;
-	if (iflags & XIVE_SRC_TRIGGER_PAGE)
+
+	/* OPAL_XIVE_IRQ_TRIGGER_PAGE is only meant to be set if
+	 * the interrupt has a *separate* trigger page.
+	 */
+	if ((iflags & XIVE_SRC_EOI_PAGE1) &&
+	    (iflags & XIVE_SRC_TRIGGER_PAGE))
 		oflags |= OPAL_XIVE_IRQ_TRIGGER_PAGE;
+
 	if (iflags & XIVE_SRC_LSI)
 		oflags |= OPAL_XIVE_IRQ_LSI;
 	if (iflags & XIVE_SRC_SHIFT_BUG)
@@ -3422,14 +3428,17 @@ static int64_t opal_xive_get_irq_info(uint32_t girq,
 
 	mm_base = (uint64_t)s->esb_mmio + (1ull << s->esb_shift) * idx;
 
+	/* The EOI page can either be the first or second page */
 	if (s->flags & XIVE_SRC_EOI_PAGE1) {
 		uint64_t p1off = 1ull << (s->esb_shift - 1);
 		eoi_page = mm_base + p1off;
-		if (s->flags & XIVE_SRC_TRIGGER_PAGE)
-			trig_page = mm_base;
 	} else
 		eoi_page = mm_base;
 
+	/* The trigger page, if it exists, is always the first page */
+	if (s->flags & XIVE_SRC_TRIGGER_PAGE)
+		trig_page = mm_base;
+
 	if (out_eoi_page)
 		*out_eoi_page = eoi_page;
 	if (out_trig_page)
diff --git a/include/xive.h b/include/xive.h
index 06aad8b..d2ef1d9 100644
--- a/include/xive.h
+++ b/include/xive.h
@@ -447,11 +447,15 @@ uint64_t xive_get_notify_port(uint32_t chip_id, uint32_t ent);
 uint32_t xive_get_notify_base(uint32_t girq);
 
 /* Internal IRQ flags */
-#define XIVE_SRC_TRIGGER_PAGE	0x01
-#define XIVE_SRC_EOI_PAGE1	0x02
-#define XIVE_SRC_STORE_EOI	0x04
-#define XIVE_SRC_LSI		0x08
-#define XIVE_SRC_SHIFT_BUG	0x10
+#define XIVE_SRC_TRIGGER_PAGE	0x01 /* Trigger page exist (either separate
+				      * or not, so different from the OPAL
+				      * flag which is only set when the
+				      * trigger page is separate).
+				      */
+#define XIVE_SRC_EOI_PAGE1	0x02 /* EOI on the second page */
+#define XIVE_SRC_STORE_EOI	0x04 /* EOI using stores supported */
+#define XIVE_SRC_LSI		0x08 /* Interrupt is an LSI */
+#define XIVE_SRC_SHIFT_BUG	0x10 /* ESB update offset << 4 */
 
 struct irq_source_ops;
 void xive_register_hw_source(uint32_t base, uint32_t count, uint32_t shift,
-- 
2.9.3



More information about the Skiboot mailing list