diff options
| -rw-r--r-- | hw/intc/xive.c | 51 | ||||
| -rw-r--r-- | include/hw/ppc/xive.h | 4 |
2 files changed, 46 insertions, 9 deletions
diff --git a/hw/intc/xive.c b/hw/intc/xive.c index b35d2ec179..8537cad27b 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -25,6 +25,45 @@ /* * XIVE Thread Interrupt Management context */ +bool xive_nsr_indicates_exception(uint8_t ring, uint8_t nsr) +{ + switch (ring) { + case TM_QW1_OS: + return !!(nsr & TM_QW1_NSR_EO); + case TM_QW2_HV_POOL: + case TM_QW3_HV_PHYS: + return !!(nsr & TM_QW3_NSR_HE); + default: + g_assert_not_reached(); + } +} + +bool xive_nsr_indicates_group_exception(uint8_t ring, uint8_t nsr) +{ + if ((nsr & TM_NSR_GRP_LVL) > 0) { + g_assert(xive_nsr_indicates_exception(ring, nsr)); + return true; + } + return false; +} + +uint8_t xive_nsr_exception_ring(uint8_t ring, uint8_t nsr) +{ + /* NSR determines if pool/phys ring is for phys or pool interrupt */ + if ((ring == TM_QW3_HV_PHYS) || (ring == TM_QW2_HV_POOL)) { + uint8_t he = (nsr & TM_QW3_NSR_HE) >> 6; + + if (he == TM_QW3_NSR_HE_PHYS) { + return TM_QW3_HV_PHYS; + } else if (he == TM_QW3_NSR_HE_POOL) { + return TM_QW2_HV_POOL; + } else { + /* Don't support LSI mode */ + g_assert_not_reached(); + } + } + return ring; +} static qemu_irq xive_tctx_output(XiveTCTX *tctx, uint8_t ring) { @@ -48,18 +87,12 @@ static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring) qemu_irq_lower(xive_tctx_output(tctx, ring)); - if (regs[TM_NSR] != 0) { + if (xive_nsr_indicates_exception(ring, nsr)) { uint8_t cppr = regs[TM_PIPR]; uint8_t alt_ring; uint8_t *alt_regs; - /* POOL interrupt uses IPB in QW2, POOL ring */ - if ((ring == TM_QW3_HV_PHYS) && - ((nsr & TM_QW3_NSR_HE) == (TM_QW3_NSR_HE_POOL << 6))) { - alt_ring = TM_QW2_HV_POOL; - } else { - alt_ring = ring; - } + alt_ring = xive_nsr_exception_ring(ring, nsr); alt_regs = &tctx->regs[alt_ring]; regs[TM_CPPR] = cppr; @@ -68,7 +101,7 @@ static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring) * If the interrupt was for a specific VP, reset the pending * buffer bit, otherwise clear the logical server indicator */ - if (!(regs[TM_NSR] & TM_NSR_GRP_LVL)) { + if (!xive_nsr_indicates_group_exception(ring, nsr)) { alt_regs[TM_IPB] &= ~xive_priority_to_ipb(cppr); } diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 538f438681..28f0f1b79a 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -365,6 +365,10 @@ static inline uint32_t xive_tctx_word2(uint8_t *ring) return *((uint32_t *) &ring[TM_WORD2]); } +bool xive_nsr_indicates_exception(uint8_t ring, uint8_t nsr); +bool xive_nsr_indicates_group_exception(uint8_t ring, uint8_t nsr); +uint8_t xive_nsr_exception_ring(uint8_t ring, uint8_t nsr); + /* * XIVE Router */ |