diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 51 |
1 files changed, 46 insertions, 5 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 7bd1b26..be91f6d 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -47066,7 +47066,29 @@ static void svc_scrub_one(struct nv_vgpu_device *vgpu, struct svc_scrub *s) if (svc_scrubs[j].registered && !svc_scrubs[j].userd_ok && svc_scrubs[j].hsem_pa == s->hsem_pa) { - pr_info("sema-svc: scrub dedup slot %d (stash owns hsem_pa=0x%llx)\n", + /* + * CONT.416: merge the scanner + * registration onto the stash + * record instead of dropping it. + * Dropping it left this record + * registered=false, so the next + * authoring pass wrote the + * blocking pair (sema=entries-1, + * fin=0) to the very page the + * guest waited on (r1749/r1752: + * Xorg's PMA scrub wait never + * ended). The wait needs the + * all-ones release, which only + * registered records author. + */ + if (!s->registered || + s->fin_pa != svc_scrubs[j].fin_pa) { + s->registered = true; + s->fin_pa = svc_scrubs[j].fin_pa; + s->pa_gen++; + s->seeded = false; + } + pr_info("sema-svc: scrub dedup slot %d (stash owns hsem_pa=0x%llx; registration merged)\n", j, s->hsem_pa); memset(&svc_scrubs[j], 0, sizeof(svc_scrubs[j])); @@ -47162,7 +47184,7 @@ static void svc_scrub_one(struct nv_vgpu_device *vgpu, struct svc_scrub *s) s->consumed = put ? put - 1 : s->entries - 1; } else if (s->submitted == s->authored && s->authored_gen == s->pa_gen && - !(s->registered && !s->submitted)) { + !s->registered) { /* * CONT.414: re-author the release pair every pass while a * scanner-registered buffer has no observed submissions, so a @@ -47202,10 +47224,29 @@ static void svc_scrub_one(struct nv_vgpu_device *vgpu, struct svc_scrub *s) * and the folded finish counter is at its maximum. */ { - bool release = s->registered && !s->submitted; + /* + * CONT.416: a scanner-registered record always takes the + * all-ones release. The PMA scrub wait (mem_scrub + * _scrubWaitAndSave; finish word at vmap+0x6c004) has no + * timeout, and the registered page is by definition the one + * the guest polled. The put-based values remain for + * stash-only records (no scanner registration). + * + * CONT.417 (reboot #2 cold-boot decision, previously "candidate" + * in the CONT.416 note): the finish word is all-ones for EVERY + * registered record (not just submitted==0), because the finish + * wait accepts only fin >= lastSeen+itemsToSave and the + * emulation never executes the memsets; the sema word stays + * put-based once real submissions were observed so an active + * scrubber still sees forward progress. 0xffffffff can never + * equal a putIndex below the ring size, so the free-entry wait + * cannot block either way. + */ + bool rel_sema = s->registered && !s->submitted; + bool rel_fin = s->registered; u32 idle = 0xffffffffu; - u32 sema = release ? idle : s->consumed; - u32 fin = release ? idle : (u32)s->submitted; + u32 sema = rel_sema ? idle : s->consumed; + u32 fin = rel_fin ? idle : (u32)s->submitted; svc_write_ap(vgpu, s->hsem_pa, SVC_APERTURE_SYS, &sema, sizeof(sema)); |
