summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index d3f73c4..dcc998b 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -6317,6 +6317,55 @@ MODULE_PARM_DESC(sema_gl_shsurf_kick,
#define SVC_GLSHSURF_VA 0x420a00800ULL
+/*
+ * r1780 (CONT.431b): direct sync of an operator-injected shared-surface page
+ * (sema_map_add). The VAS walk cannot always name the client incarnation, but
+ * a verified {known shared-surface VA -> page} pin is authoritative: read the
+ * page's lastKickoffRefCount and author it into gpuRefCount[0] forward-only.
+ * This is the live unblock for the DDX idle wait when the page has already
+ * been identified by the strict signature scan.
+ */
+static void svc_gl_shsurf_pin_sync(struct nv_vgpu_device *vgpu)
+{
+ u64 lkr = 0, pa = 0;
+ u32 cur = 0, want;
+ int ap = SVC_APERTURE_SYS;
+ static u32 log;
+
+ /*
+ * svc_pin_lookup_any returns 0 on a hit (Linux convention); try the
+ * exact VA first, then the page-aligned form the commands use.
+ */
+ if (!svc_pin_lookup_any(SVC_GLSHSURF_VA, &pa, &ap)) {
+ /* exact VA hit: use its translation */
+ } else if (!svc_pin_lookup_any(SVC_GLSHSURF_VA & ~0xfffULL,
+ &pa, &ap)) {
+ /* page-aligned hit: use its translation */
+ } else {
+ return;
+ }
+ if (svc_read_ap(vgpu, (pa & ~0xfffULL) | 0x880ULL, ap,
+ &lkr, sizeof(lkr)))
+ return;
+ if ((lkr >> 32) || !(lkr & 0xffffffffULL) ||
+ (lkr & 0xffffffffULL) > 0x1000000ULL)
+ return;
+ want = (u32)lkr;
+ if (svc_read_ap(vgpu, (pa & ~0xfffULL) | 0x800ULL, ap, &cur,
+ sizeof(cur)))
+ return;
+ if (cur >= want)
+ return;
+ if (svc_write_ap(vgpu, (pa & ~0xfffULL) | 0x800ULL, ap, &want,
+ sizeof(want)))
+ return;
+ if (log < 64) {
+ log++;
+ pr_info("sema-gl: shsurf-pin-sync pa=0x%llx cur=%u lkr=0x%llx\n",
+ pa, cur, lkr);
+ }
+}
+
static bool svc_gl_shsurf_sync(struct nv_vgpu_device *vgpu, u32 h, u64 va,
u32 val)
{
@@ -31111,6 +31160,62 @@ static void svc_xvas_pdb_discover(struct nv_vgpu_device *vgpu, u64 ring_va,
return;
}
}
+ /*
+ * r1780 (CONT.431): the COPY_SERVER_PDES candidates are the only
+ * known addresses of the client's page-directory incarnations, and
+ * the correct incarnation is frequently allocated next to an
+ * offered one (the driver rebuilds the directory in the same pool).
+ * Scan a bounded window around every candidate pdb for a root that
+ * reproduces the verified ring pair and register it under the
+ * candidate's VAS handle, so the channel's own VAS lookup resolves
+ * the ring even when the offered pdb itself is stale. The walk is
+ * the proof; a wrong page cannot register.
+ */
+ {
+ static const u32 cand_ent[] = { 4, 8, 16, 32 };
+ u32 ci, ei2;
+
+ for (ci = 0; ci < SVC_VAS_CAND_MAX; ci++) {
+ u64 base = svc_vas_cand[ci].pdb;
+ u64 lo, hi, poff;
+ u32 hvas = svc_vas_cand[ci].h_vaspace;
+
+ if (!base)
+ continue;
+ lo = (base > 0x400000ULL) ? base - 0x400000ULL
+ : 0x1000ULL;
+ hi = base + 0x400000ULL;
+ if (hi > svc_pa_max())
+ hi = svc_pa_max();
+ for (poff = lo & ~0xfffULL; poff < hi;
+ poff += 0x1000ULL) {
+ for (ei2 = 0; ei2 < ARRAY_SIZE(cand_ent);
+ ei2++) {
+ if (!svc_xvas_try_root(vgpu, poff,
+ cand_ent[ei2],
+ false, ring_va,
+ ring_pa))
+ continue;
+ if (hvas) {
+ struct sema_vaspace_desc d;
+
+ memset(&d, 0, sizeof(d));
+ d.h_vaspace = hvas;
+ d.pdb = poff;
+ d.num_entries = cand_ent[ei2];
+ d.b_vidmem = false;
+ d.verified = true;
+ gsp_sema_service_vaspace_add(&d);
+ pr_info("sema-svc: VAS 0x%x registered from candidate-neighbourhood pdb=0x%llx entries=%u (ring 0x%llx -> 0x%llx verified)\n",
+ hvas, poff,
+ cand_ent[ei2],
+ ring_va, ring_pa);
+ }
+ return;
+ }
+ }
+ }
+ }
}
/*
@@ -43240,6 +43345,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
if (sva != SVC_GLSHSURF_VA)
(void)svc_gl_shsurf_sync(vgpu, 0,
SVC_GLSHSURF_VA, 0);
+ svc_gl_shsurf_pin_sync(vgpu);
}
}
/* Only ever called from the service thread. */