summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_emulation.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_emulation.c')
-rw-r--r--kernel/gsp_emulation.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/kernel/gsp_emulation.c b/kernel/gsp_emulation.c
index 47c8151..38f6284 100644
--- a/kernel/gsp_emulation.c
+++ b/kernel/gsp_emulation.c
@@ -644,6 +644,63 @@ void gsp_emu_inject_completion_interrupt(struct gsp_emu_context *ctx, u32 seq_id
eventfd_signal(trigger);
}
+/*
+ * Raise the GSP engine event interrupt.
+ *
+ * Mirrors what a real GSP-RM does when it queues an event for the host:
+ * - program the RISC-V interrupt mask/destination so SWGEN0 is routed to
+ * the CPU (read-only to the guest; the GSP firmware owns them),
+ * - set SWGEN0 in the falcon IRQSTAT,
+ * - latch the GSP stall vector (155) in the host CPU interrupt tree:
+ * LEAF[4] bit 27 and TOP[0] bit 2 (UVM_SHARED subtree 2),
+ * - signal MSI-X.
+ *
+ * Without the leaf bit the guest's primary ISR returns IRQ_NONE and the
+ * threaded handler (kgspService_TU102 -> kgspRpcRecvEvents -> nv_post_event)
+ * never runs, so a client blocked in poll() on /dev/nvidia0 (a GLX swap)
+ * waits forever even though the event is sitting in the status queue.
+ */
+void gsp_emu_raise_gsp_event_irq(struct gsp_emu_context *ctx)
+{
+ u32 reg, val;
+ u32 leaf_idx = GSP_EMU_GSP_EVENT_VECTOR / 32;
+ u32 leaf_bit = GSP_EMU_GSP_EVENT_VECTOR % 32;
+ u32 subtree = GSP_EMU_GSP_EVENT_VECTOR / 64;
+ u32 top_idx = subtree / 32;
+ u32 top_bit = subtree % 32;
+
+ if (!ctx || !ctx->bar0_vaddr)
+ return;
+
+ /* IRQMASK / IRQDEST: route SWGEN0 to the CPU (idempotent). */
+ reg = GSP_EMU_REG_RISCV_IRQMASK;
+ val = gsp_emu_shadow_read32(ctx, reg);
+ if (!(val & GSP_EMU_FALCON_IRQSTAT_SWGEN0))
+ gsp_emu_shadow_write32(ctx, reg,
+ val | GSP_EMU_FALCON_IRQSTAT_SWGEN0);
+ reg = GSP_EMU_REG_RISCV_IRQDEST;
+ val = gsp_emu_shadow_read32(ctx, reg);
+ if (!(val & GSP_EMU_FALCON_IRQSTAT_SWGEN0))
+ gsp_emu_shadow_write32(ctx, reg,
+ val | GSP_EMU_FALCON_IRQSTAT_SWGEN0);
+
+ /* Pending source: SWGEN0. */
+ reg = GSP_EMU_REG_FALCON_IRQSTAT;
+ val = gsp_emu_shadow_read32(ctx, reg);
+ gsp_emu_shadow_write32(ctx, reg,
+ val | GSP_EMU_FALCON_IRQSTAT_SWGEN0);
+
+ /* CPU interrupt tree: LEAF[leaf_idx] |= bit, TOP[top_idx] |= bit. */
+ reg = GSP_EMU_REG_CPU_INTR_LEAF_BASE + leaf_idx * 4;
+ val = gsp_emu_shadow_read32(ctx, reg);
+ gsp_emu_shadow_write32(ctx, reg, val | (1U << leaf_bit));
+ reg = GSP_EMU_REG_CPU_INTR_TOP_BASE + top_idx * 4;
+ val = gsp_emu_shadow_read32(ctx, reg);
+ gsp_emu_shadow_write32(ctx, reg, val | (1U << top_bit));
+
+ gsp_emu_inject_completion_interrupt(ctx, 0);
+}
+
/* ============================================================
* Emulation Thread
* ============================================================ */