From 3701f985edb89224f6a5c1237b21ddb8e527e126 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 9 Nov 2026 14:05:39 -0500 Subject: vgsp-sema: resolve the scrubber's finish words through the GPU page tables The guest PMA scrubber's host-side completion (channel buffer + pbSize + entries*8) was resolved through the learned VA->PA pair map first. When the guest reused the scrubber's GPU VA for a new channel buffer, that map still named the previous allocation's page, and the host authored the finish payload there while the guest polled the new page through its kernel VAS (h=0xc). r1667 live proof: walk_probe 0x12006c000 -> only VAS[1] (h=0xc) resolves to PA 0x10812a000 (the page the guest's vmalloc mapping of the channel buffer points at, and the value it polls); the pair map returned 0x10526a000. Writing the finish value to the correct page (via the guest scanner registration) immediately released Xorg from the RM memory-manager wait and the queued GSP status records drained. Changes: - svc_scrub_pass(): resolve hsem/fin through svc_walk_vaspaces() first, fall back to the pair map only when no VAS maps the VA. - Struct svc_scrub gains authored_gen; a new pa_gen (fresh scanner registration or a corrected derivation) forces one authoring pass even when the scrubber's PUT did not advance, so an already-waiting guest is released without a new submission. --- kernel/gsp_sema_service.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 1b77ea0..7f61c57 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -1068,6 +1068,7 @@ struct svc_scrub { u32 put_last; u64 submitted; /* blocks submitted since seeding */ u64 authored; /* last authored finish value */ + u32 authored_gen; /* pa_gen at the last authored write */ u32 pa_gen; /* scanner registration generation (logged) */ u32 session_gen; /* m176: session generation of the last registration */ u32 log_budget; @@ -45344,8 +45345,17 @@ static void svc_scrub_pass(struct nv_vgpu_device *vgpu) u64 pa = 0; int ap = SVC_APERTURE_SYS; - if (svc_lookup(vgpu, hva, &pa, &ap) || !pa) { - if (svc_walk_vaspaces(vgpu, hva, &pa, &ap) || !pa) + /* + * r1667: resolve through the GPU page tables FIRST. The learned + * VA->PA pair map can name a stale page for a reused VA (the guest + * polls its scrubber finish word through the kernel VAS h=0xc, + * which the walk resolves correctly, while svc_lookup returned an + * old page from a previous allocation and the scrub wait never + * completed). Fall back to the pair map only when no walkable VAS + * maps the VA. + */ + if (svc_walk_vaspaces(vgpu, hva, &pa, &ap) || !pa) { + if (svc_lookup(vgpu, hva, &pa, &ap) || !pa) pa = 0; } /* The scrub words are guest RAM; an FB translation is not. */ @@ -45412,7 +45422,8 @@ static void svc_scrub_pass(struct nv_vgpu_device *vgpu) delta = s->entries; /* exact wrap */ s->submitted += delta; s->put_last = put; - } else if (s->submitted == s->authored) { + } else if (s->submitted == s->authored && + s->authored_gen == s->pa_gen) { return; /* nothing new; no guest writes */ } @@ -45438,6 +45449,7 @@ static void svc_scrub_pass(struct nv_vgpu_device *vgpu) sizeof(fin)); } s->authored = s->submitted; + s->authored_gen = s->pa_gen; } /* -- cgit v1.2.3