aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2025-05-12 13:10:40 +1000
committerCédric Le Goater <clg@redhat.com>2025-07-21 08:03:52 +0200
commit46f5ee8885a521c56e60820bf35aba4e94e16cf7 (patch)
tree124b4e2fcbbc17916f837c07991a331ec8f7e339
parentd16214ed2c57a31b5de7e2c115c65b831170a60e (diff)
downloadqemu-46f5ee8885a521c56e60820bf35aba4e94e16cf7.zip
qemu-46f5ee8885a521c56e60820bf35aba4e94e16cf7.tar.gz
qemu-46f5ee8885a521c56e60820bf35aba4e94e16cf7.tar.bz2
ppc/xive: Fix high prio group interrupt being preempted by low prio VP
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>
-rw-r--r--hw/intc/xive.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 038c358..7110cf4 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -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);
}
/*