summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 8e6401d..7bd1b26 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -47161,7 +47161,13 @@ static void svc_scrub_one(struct nv_vgpu_device *vgpu, struct svc_scrub *s)
s->put_last = put;
s->consumed = put ? put - 1 : s->entries - 1;
} else if (s->submitted == s->authored &&
- s->authored_gen == s->pa_gen) {
+ s->authored_gen == s->pa_gen &&
+ !(s->registered && !s->submitted)) {
+ /*
+ * CONT.414: re-author the release pair every pass while a
+ * scanner-registered buffer has no observed submissions, so a
+ * guest rewrite of the polled word cannot re-block the wait.
+ */
return; /* nothing new; no guest writes */
}
@@ -47181,15 +47187,28 @@ static void svc_scrub_one(struct nv_vgpu_device *vgpu, struct svc_scrub *s)
*/
svc_write_ap(vgpu, s->userd_pa + SVC_USERD_GP_GET, s->userd_as,
&put, sizeof(put));
+ /*
+ * CONT.414: a scanner-registered channel buffer with no observed
+ * USERD GP_PUT submissions is the X DDX's vidheap scrub wait: the
+ * guest RM polls the finish payload at channel buffer + 0x6c004
+ * (channelWaitForFinishPayload) while the host still reads GP_PUT=0,
+ * so the put-based forward authoring would write sema=entries-1 and
+ * fin=0 - the exact values that leave channelWaitForFreeEntry and
+ * channelWaitForFinishPayload blocked (r1729: Xorg holds the NVRM
+ * RM API write lock in that wait, glxgears and nvidia-modeset D on
+ * os_acquire_rwlock_write). Author the proven all-ones release pair
+ * (CONT.408/409) until a real put advance gives us progress to
+ * mirror; 0xffffffff can never equal a putIndex below the ring size
+ * and the folded finish counter is at its maximum.
+ */
{
- u32 sema = s->consumed;
+ bool release = s->registered && !s->submitted;
+ u32 idle = 0xffffffffu;
+ u32 sema = release ? idle : s->consumed;
+ u32 fin = release ? idle : (u32)s->submitted;
svc_write_ap(vgpu, s->hsem_pa, SVC_APERTURE_SYS, &sema,
sizeof(sema));
- }
- {
- u32 fin = (u32)s->submitted;
-
svc_write_ap(vgpu, s->fin_pa, SVC_APERTURE_SYS, &fin,
sizeof(fin));
}