diff options
Diffstat (limited to 'kernel/gsp_emulation.c')
| -rw-r--r-- | kernel/gsp_emulation.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/kernel/gsp_emulation.c b/kernel/gsp_emulation.c index 38f6284..b82bab1 100644 --- a/kernel/gsp_emulation.c +++ b/kernel/gsp_emulation.c @@ -705,6 +705,38 @@ void gsp_emu_raise_gsp_event_irq(struct gsp_emu_context *ctx) * Emulation Thread * ============================================================ */ +/* Advance the emulated GPU PTIMER (NV_PTIMER_TIME_0/1 at BAR0 0x9400/0x9410). + * + * The guest's nvidia.ko RM uses this register as its time source for timed + * waits (e.g. _nv015102rm -> _nv018147rm -> _nv018351rm). BAR0 is a plain + * host shadow mapped to the guest, so nothing advances these registers by + * default: every RM deadline becomes unreachable and the DDX/GL client + * spins forever inside the driver (observed as an Xorg hang at GDI/window + * creation). Seed from the existing value to keep time continuous, then + * advance by the host monotonic clock. + */ +static void gsp_emu_tick_ptimer(struct gsp_emu_context *ctx) +{ + u64 now, val; + + if (!ctx->bar0_vaddr) + return; + + now = ktime_get_ns(); + if (!ctx->ptimer_seeded) { + u32 lo = gsp_emu_shadow_read32(ctx, 0x9400); + u32 hi = gsp_emu_shadow_read32(ctx, 0x9410); + + ctx->ptimer_base = ((u64)hi << 32) | lo; + ctx->ptimer_t0 = now; + ctx->ptimer_seeded = true; + } + + val = ctx->ptimer_base + (now - ctx->ptimer_t0); + gsp_emu_shadow_write32(ctx, 0x9400, (u32)val); + gsp_emu_shadow_write32(ctx, 0x9410, (u32)(val >> 32)); +} + static int gsp_emu_thread_fn(void *data) { struct gsp_emu_context *ctx = data; @@ -716,6 +748,9 @@ static int gsp_emu_thread_fn(void *data) nv_vgpu_info(ctx->vgpu, "GSP emulation thread started"); while (!kthread_should_stop()) { + /* Keep the guest-visible GPU timer advancing (RM timed waits) */ + gsp_emu_tick_ptimer(ctx); + /* Read doorbell */ doorbell_val = gsp_emu_read_doorbell(ctx); |
