diff options
Diffstat (limited to 'kernel/gsp_emulation.c')
| -rw-r--r-- | kernel/gsp_emulation.c | 57 |
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 * ============================================================ */ |
