]> git.ipfire.org Git - thirdparty/qemu.git/commitdiff
ppc/xive: Fix high prio group interrupt being preempted by low prio VP
authorNicholas Piggin <npiggin@gmail.com>
Mon, 12 May 2025 03:10:40 +0000 (13:10 +1000)
committerCédric Le Goater <clg@redhat.com>
Mon, 21 Jul 2025 06:03:52 +0000 (08:03 +0200)
xive_tctx_pipr_present() as implemented with xive_tctx_pipr_update()
causes VP-directed (group==0) interrupt to be presented in PIPR and NSR
despite being a lower priority than the currently presented group
interrupt.

This must not happen. The IPB bit should record the low priority VP
interrupt, but PIPR and NSR must not present the lower priority
interrupt.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Glenn Miles <milesg@linux.ibm.com>
Reviewed-by: Michael Kowal <kowal@linux.ibm.com>
Tested-by: Gautam Menghani <gautam@linux.ibm.com>
Link: https://lore.kernel.org/qemu-devel/20250512031100.439842-32-npiggin@gmail.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
hw/intc/xive.c

index 038c35846d94716a85e450165c9ade7f3cec0127..7110cf45d74f9f8e7cace545b63760a7c1c0043a 100644 (file)
@@ -228,7 +228,23 @@ void xive_tctx_pipr_update(XiveTCTX *tctx, uint8_t ring, uint8_t priority,
 void xive_tctx_pipr_present(XiveTCTX *tctx, uint8_t ring, uint8_t priority,
                             uint8_t group_level)
 {
-    xive_tctx_pipr_update(tctx, ring, priority, group_level);
+    /* HV_POOL ring uses HV_PHYS NSR, CPPR and PIPR registers */
+    uint8_t alt_ring = (ring == TM_QW2_HV_POOL) ? TM_QW3_HV_PHYS : ring;
+    uint8_t *aregs = &tctx->regs[alt_ring];
+    uint8_t *regs = &tctx->regs[ring];
+    uint8_t pipr = xive_priority_to_pipr(priority);
+
+    if (group_level == 0) {
+        regs[TM_IPB] |= xive_priority_to_ipb(priority);
+        if (pipr >= aregs[TM_PIPR]) {
+            /* VP interrupts can come here with lower priority than PIPR */
+            return;
+        }
+    }
+    g_assert(pipr <= xive_ipb_to_pipr(regs[TM_IPB]));
+    g_assert(pipr < aregs[TM_PIPR]);
+    aregs[TM_PIPR] = pipr;
+    xive_tctx_notify(tctx, ring, group_level);
 }
 
 /*