diff options
Diffstat (limited to 'hw/intc/xive2.c')
| -rw-r--r-- | hw/intc/xive2.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c index 3720e70422..048b98dbbe 100644 --- a/hw/intc/xive2.c +++ b/hw/intc/xive2.c @@ -159,6 +159,101 @@ static void xive2_end_enqueue(Xive2End *end, uint32_t data) } end->w1 = xive_set_field32(END2_W1_PAGE_OFF, end->w1, qindex); } + +/* + * XIVE Thread Interrupt Management Area (TIMA) - Gen2 mode + */ + +static void xive2_os_cam_decode(uint32_t cam, uint8_t *nvp_blk, + uint32_t *nvp_idx, bool *vo) +{ + *nvp_blk = xive2_nvp_blk(cam); + *nvp_idx = xive2_nvp_idx(cam); + *vo = !!(cam & TM2_QW1W2_VO); +} + +uint64_t xive2_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx, + hwaddr offset, unsigned size) +{ + uint32_t qw1w2 = xive_tctx_word2(&tctx->regs[TM_QW1_OS]); + uint32_t qw1w2_new; + uint32_t cam = be32_to_cpu(qw1w2); + uint8_t nvp_blk; + uint32_t nvp_idx; + bool vo; + + xive2_os_cam_decode(cam, &nvp_blk, &nvp_idx, &vo); + + if (!vo) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: pulling invalid NVP %x/%x !?\n", + nvp_blk, nvp_idx); + } + + /* Invalidate CAM line */ + qw1w2_new = xive_set_field32(TM2_QW1W2_VO, qw1w2, 0); + memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2_new, 4); + + return qw1w2; +} + +static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx, + uint8_t nvp_blk, uint32_t nvp_idx) +{ + Xive2Nvp nvp; + uint8_t ipb; + uint8_t cppr = 0; + + /* + * Grab the associated thread interrupt context registers in the + * associated NVP + */ + if (xive2_router_get_nvp(xrtr, nvp_blk, nvp_idx, &nvp)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVP %x/%x\n", + nvp_blk, nvp_idx); + return; + } + + if (!xive2_nvp_is_valid(&nvp)) { + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid NVP %x/%x\n", + nvp_blk, nvp_idx); + return; + } + + ipb = xive_get_field32(NVP2_W2_IPB, nvp.w2); + if (ipb) { + nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, 0); + xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 2); + } + + /* An IPB or CPPR change can trigger a resend */ + if (ipb || cppr) { + xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb); + } +} + +/* + * Updating the OS CAM line can trigger a resend of interrupt + */ +void xive2_tm_push_os_ctx(XivePresenter *xptr, XiveTCTX *tctx, + hwaddr offset, uint64_t value, unsigned size) +{ + uint32_t cam = value; + uint32_t qw1w2 = cpu_to_be32(cam); + uint8_t nvp_blk; + uint32_t nvp_idx; + bool vo; + + xive2_os_cam_decode(cam, &nvp_blk, &nvp_idx, &vo); + + /* First update the thead context */ + memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4); + + /* Check the interrupt pending bits */ + if (vo) { + xive2_tctx_need_resend(XIVE2_ROUTER(xptr), tctx, nvp_blk, nvp_idx); + } +} + /* * XIVE Router (aka. Virtualization Controller or IVRE) */ |