diff options
Diffstat (limited to 'kernel/gsp_emulation.h')
| -rw-r--r-- | kernel/gsp_emulation.h | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/kernel/gsp_emulation.h b/kernel/gsp_emulation.h index 9a8f241..16f4db4 100644 --- a/kernel/gsp_emulation.h +++ b/kernel/gsp_emulation.h @@ -116,6 +116,29 @@ #define GSP_EMU_REG_CPU_INTR_LEAF_BASE (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x1000) #define GSP_EMU_REG_CPU_INTR_TOP_BASE (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x1600) +/* GSP event interrupt (Turing, physical-GPU path). + * + * A real GSP-RM posts an event into the status queue and raises the GSP + * engine interrupt: it sets SWGEN0 in the falcon IRQSTAT and the host CPU's + * interrupt tree latches the GSP stall vector (155 = LEAF[4] bit 27, UVM_SHARED + * subtree 2 -> TOP[0] bit 2). The guest's primary ISR (nvidia_isr) then + * returns IRQ_WAKE_THREAD, kgspService_TU102 reads + * IRQSTAT & RISCV_IRQMASK & RISCV_IRQDEST, sees SWGEN0, calls + * kgspRpcRecvEvents -> nv_post_event -> wake_up_interruptible, which is what + * releases a client blocked in poll() on /dev/nvidia0 (e.g. a GLX swap). + * + * We were only signalling the MSI-X eventfd, so the primary ISR returned + * IRQ_NONE (no pending leaf bit) and the event thread never ran: IRQ 33 + * counted thousands of interrupts while the guest's nvidia worker threads sat + * idle and the client polled forever. IRQMASK/IRQDEST are read-only to the + * guest (the GSP firmware owns them), so the emulated GSP must program them. */ +#define GSP_EMU_REG_FALCON_IRQSCLR 0x110004 /* -W- : write 1 to clear */ +#define GSP_EMU_REG_FALCON_IRQSTAT 0x110008 /* R-- : pending sources */ +#define GSP_EMU_REG_RISCV_IRQMASK 0x1112b4 /* R-I : enabled sources */ +#define GSP_EMU_REG_RISCV_IRQDEST 0x1112b8 /* RW : routed to CPU */ +#define GSP_EMU_FALCON_IRQSTAT_SWGEN0 (1U << 6) +#define GSP_EMU_GSP_EVENT_VECTOR 155 /* MC_ENGINE_IDX_GSP stall */ + /* Windowed aliases of the VF L2 invalidate registers (GPU_VREG_* path). */ #define GSP_EMU_REG_VF_L2_SYSMEM_INV_WIN (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x000f00) #define GSP_EMU_REG_VF_L2_PEERMEM_INV_WIN (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x000f04) @@ -169,6 +192,14 @@ struct gsp_emu_context { u32 bar0_window_base; /* last-seen NV_PBUS_BAR0_WINDOW BASE (page) */ u32 bar0_window_target; /* last-seen TARGET (0=vidmem, 2/3=sysmem) */ bool bar0_window_valid; /* base/target captured at least once */ + + /* Emulated PTIMER (BAR0 0x9400/0x9410): the guest RM's time source. + * Seeded from the shadow's current 64-bit value on the first tick so + * the guest-observed time stays continuous, then advanced by the host + * monotonic clock. Without this the RM's timed waits never expire. */ + u64 ptimer_base; + u64 ptimer_t0; + bool ptimer_seeded; }; /* Shadow accessors shared with gsp_rm_emulation.c */ @@ -195,6 +226,9 @@ void gsp_emu_cleanup(struct nv_vgpu_device *vgpu); void gsp_emu_clear_boot_state(struct gsp_emu_context *ctx, const char *reason); int gsp_emu_process_rpc(struct gsp_emu_context *ctx); void gsp_emu_inject_completion_interrupt(struct gsp_emu_context *ctx, u32 seq_id); +/* Raise the GSP event interrupt (falcon SWGEN0 + CPU_INTR leaf/top + MSI-X) + * so the guest's ISR drains the status queue and wakes poll() waiters. */ +void gsp_emu_raise_gsp_event_irq(struct gsp_emu_context *ctx); /* ============================================================ * Debug/Statistics |
