From 00319db208aa8fa90b6ad03ef154815ed86d8225 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Tue, 27 Oct 2026 17:05:10 -0400 Subject: vgsp: xw-mirror writes one learned frame-step ahead of the counter r866: the mirror tracked perfectly yet every wait still paid the driver's ~3 s re-check sleep (one '(0)' success print every 20-80 s; the GL client hung minutes on its X socket). Cause: the driver increments its counter and then enters the wait; a member that only tracks the counter always loses that entry-check race (mirror wakes <=3 ms after the change; the driver probes within microseconds), so the check fails and the driver sleeps out its retry interval. Writing member = counter + last-observed- delta (learned from each counter change, 0 until the first) makes the driver's own increment land exactly on the pre-written member value, so the first probe after submission succeeds and frames complete at the driver's pace. --- kernel/gsp_sema_service.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index af4534b..471f5ae 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -30528,6 +30528,8 @@ int gsp_sema_service_add_map(u64 gpu_va, u64 pa, u64 len, u32 ap) */ static u64 svc_xw_cnt_pa; static u64 svc_xw_mem_pa; +static u32 svc_xw_last_c; /* last counter read (delta learning) */ +static u32 svc_xw_delta; /* last observed per-frame counter step */ static struct task_struct *svc_xw_task; static int svc_xw_mirror_loop(void *unused) @@ -30549,9 +30551,31 @@ static int svc_xw_mirror_loop(void *unused) &c, sizeof(c)) && !svc_read_ap(vgpu, svc_xw_mem_pa, SVC_APERTURE_SYS, &cur, sizeof(cur))) { - u32 m = (cur & 0xfffc0000u) | - ((c >> 2) & 0x3ffffu); - + u32 m; + /* + * SESSION 148 (r866): write the member one learned + * frame-step AHEAD of the counter. The driver's + * frame path increments its counter and *then* + * enters the wait; a member that only tracks the + * counter therefore always loses that entry-check + * race (mirror latency > driver gap) and each wait + * pays the driver's ~3 s re-check sleep - measured + * as one "(0)" success print every 20-80 s and a + * client hanging on its X socket for minutes. + * With member = counter + last-delta the driver's + * check succeeds on the FIRST probe after its own + * increment (the increment lands exactly on the + * pre-written value), so frames complete at the + * driver's own pace. Delta is learned from each + * observed counter change; 0 until the first change. + */ + if (c != svc_xw_last_c) { + if (svc_xw_last_c) + svc_xw_delta = c - svc_xw_last_c; + svc_xw_last_c = c; + } + m = (cur & 0xfffc0000u) | + (((u64)(c + svc_xw_delta) >> 2) & 0x3ffffu); if (m != cur) svc_write_ap(vgpu, svc_xw_mem_pa, SVC_APERTURE_SYS, &m, sizeof(m)); -- cgit v1.2.3