From 2d0a65b8f10f8bfac935d880dd9704e7b14f5b29 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Sun, 11 Oct 2026 17:35:54 -0400 Subject: vgsp-sema: keep the scrubber channel inert; publish its finish payload from GP_PUT (ISSUE-0002) The CeUtils scrubber channel (entries=4096, GPU-global) stays registered across client sessions now that deletion is client-scoped, but its channel buffer memory is reused by later clients' push buffers: entry-pumping its stale ring invented work and perturbed the session (r79/r80: the first client wedged on an rwsem). The pump now skips channels with the scrubber layout (entries >= 4096) and instead publishes the word the pma scrub actually waits on - the channel buffer finish payload at gpfifo_va + 8*entries + 4 (live-verified: 0x120064000 + 0x8000 + 4 = 0x12006c004, the address from the hung client's register dump) - forward-only from the channel's own GP_PUT (one payload per submitted push, the same counter the guest's ceutilsUpdateProgress polls). Skipping the scrub's actual memset work is acceptable for the emulated vidmem: the guest's scrub clears pages of its own shadow, and the emulation's job here is the completion contract. Revisit if per-tenant vidmem scrubbing is required. --- kernel/gsp_sema_service.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'kernel') diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 9f967a5..5f76442 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -13110,6 +13110,44 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) if (!ch->gpfifo_va || !ch->gpfifo_entries) continue; + /* + * ISSUE-0002 (r80): the CeUtils scrubber channel is a + * GPU-global kernel channel that stays registered across + * client sessions (client-scoped deletion). It must not be + * entry-pumped: its channel buffer memory is reused by later + * clients' push buffers, so decoding its stale ring invents + * work and perturbs the session (r79/r80 wedges). What the + * guest's pma scrub waits on is the channel buffer's finish + * payload at pbGpuVA + channelPbSize + gpfifo_size + 4, + * i.e. gpfifo_va + 8*entries + 4 (verified against the live + * channel object: gpfifo=0x120064000 entries=4096 -> + * 0x12006c004). Publish it forward-only from the channel's + * own GP_PUT: the guest waits for submittedWorkId <= + * payload, one payload per submitted push, and the put + * counts exactly those pushes. The scrub work itself is + * emulated vidmem maintenance; the guest reads its own + * shadow through BAR1, so completing the counter is the + * contract. + */ + if (ch->gpfifo_entries >= 4096) { + u32 sfin = 0; + + if (ch->userd_pa && + !svc_read_ap(vgpu, ch->userd_pa + SVC_USERD_GP_PUT, + ch->userd_as, &sfin, sizeof(sfin)) && + sfin) { + u64 fin_va = ch->gpfifo_va + + 8ULL * ch->gpfifo_entries + 4; + u32 fcur = 0; + + if (!svc_sem_read(vgpu, fin_va, &fcur) && + sfin > fcur) + svc_sem_write(vgpu, ch->h_object, + fin_va, sfin); + } + continue; + } + svc_ring_autopin(vgpu, ch); rrc = svc_lookup(vgpu, ch->gpfifo_va, &ring_pa, &ring_ap); -- cgit v1.2.3