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.c30
1 files 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));