summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c51
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));