From a478f0b418bd3dd5fbcc6260979865160ca25cf0 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 9 Nov 2026 19:27:48 -0500 Subject: vgsp: raise the GSP engine event interrupt so guest ISR drains events and wakes poll() waiters The emulated GSP only signalled the MSI-X eventfd when it queued a status record. The guest's primary ISR (nvidia_isr) decides pending from the CPU_INTR leaf registers, which we never set for the GSP stall vector, so it returned IRQ_NONE: IRQ 33 counted thousands of interrupts while the nvidia event thread sat idle and a client blocked in poll() on /dev/nvidia0 (a GLX swap) waited forever even though the event was already in the status queue. Mirror what a real GSP-RM does when it queues an event: - program RISC-V IRQMASK/IRQDEST for SWGEN0 (read-only to the guest; the GSP firmware owns them), - set SWGEN0 in the falcon IRQSTAT, - latch GSP stall vector 155 in the CPU interrupt tree (LEAF[4] bit 27, UVM_SHARED subtree 2 -> TOP[0] bit 2), - signal MSI-X. Raise it only for POST_EVENT records (replies are polled by the client). Verified on r1680: the guest now writes IRQSCLR SWGEN0, kgspService_TU102 drains events, and glxgears renders (was a hard hang). --- kernel/gsp_emulation.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'kernel/gsp_emulation.c') 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 * ============================================================ */ -- cgit v1.2.3