|
@@ -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)
|
|
|
*/
|