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.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index f45817b..e60b6e0 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -786,6 +786,8 @@ static u32 svc_pb_idle; /* consecutive passes with no new base */
static u32 svc_pb_last_n; /* bases before the active pass */
static unsigned long svc_pb_done; /* CE ranks whose push buffer is pinned */
static unsigned long svc_gr_ring_done; /* GR ranks whose ring is pinned */
+/* SESSION 133: ranks that already consumed their one shadow ring scan. */
+static unsigned long svc_gr_ring_scan_done;
static bool svc_pb_first_push(const u8 *buf)
{
@@ -12980,6 +12982,7 @@ static void svc_session_flush(void)
svc_pb_last = 0;
svc_pb_last_n = 0;
svc_gr_ring_done = 0;
+ svc_gr_ring_scan_done = 0;
svc_ring_n = 0;
/*
* The learned tables are session state too: the primary VA->PA pin
@@ -16279,6 +16282,83 @@ static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu,
}
}
+ /*
+ * SESSION 133: bounded shadow ring scan fallback.
+ *
+ * The CE-class rings live in VIDMEM and the FB convention only
+ * matches when the guest's VRAM allocator happens to place them at
+ * the conventional offsets (r763: matched, fb 0x80000/0xa0000, the
+ * channel decoded; r765: read zeros, the ring VA resolved to a
+ * stale RAM page whose entry0 was dead, the CE channel never
+ * latched and its inline SASS copies never decoded - black
+ * frames). When every deterministic candidate has failed, scan the
+ * shadow for a ring-shaped page: entry0 must name a 1 MB aligned
+ * push VA in the client window with a sane length, must not be
+ * provably dead (svc_ring_entry_dead - the r759 false-positive
+ * guard), and the USERD at the observed deltas (+0x10000 for the
+ * CE family, +0x2000 for GR) must read a coherent put/get. One
+ * bounded scan per rank per boot; a false candidate still costs
+ * only a failed probe.
+ */
+ if (!test_and_set_bit(ch->gr_index, &svc_gr_ring_scan_done)) {
+ u8 *sbase = vgpu->bars[1].vaddr;
+ u64 lim = min_t(u64, svc_fb_shadow_size(vgpu), 0x4000000ULL);
+ u64 off;
+
+ if (sbase && lim > 0x1000) {
+ static const u64 udeltas[] = { 0x10000, SVC_GR_USERD_OFF,
+ 0x1000 };
+
+ for (off = 0; off + 8 <= lim; off += 0x1000) {
+ u32 h0, h1;
+ u64 hva;
+ u32 hlen;
+ unsigned int ui;
+
+ memcpy(&h0, sbase + off, 4);
+ memcpy(&h1, sbase + off + 4, 4);
+ hva = ((u64)(h1 & 0xff) << 32) |
+ (u64)(h0 & 0xfffffffc);
+ hlen = ((h1 >> 10) & 0x1fffff) << 2;
+ if (!hva || (hva & 0xfffff) ||
+ hva < SEMA_VA_LO || hva >= SEMA_VA_HI ||
+ hlen < 4 || hlen > 0x10000)
+ continue;
+ if (svc_ring_entry_dead(vgpu, h0, h1))
+ continue;
+ for (ui = 0; ui < ARRAY_SIZE(udeltas); ui++) {
+ u64 upa = off + udeltas[ui];
+ u32 p3 = 0, g3 = 0;
+
+ if (upa + 4 > lim)
+ continue;
+ if (svc_userd_probe(vgpu, upa,
+ SVC_APERTURE_FB,
+ ch->gpfifo_entries,
+ &p3, &g3))
+ continue;
+ svc_pin_store(ch->gpfifo_va, off,
+ SVC_APERTURE_FB);
+ svc_lat_store(ch->gpfifo_va, off,
+ SVC_APERTURE_FB);
+ ch->userd_pa = upa;
+ ch->userd_as = SVC_APERTURE_FB;
+ ch->userd_ok = true;
+ svc_gr_ring_base = off;
+ set_bit(ch->gr_index,
+ &svc_gr_ring_done);
+ svc_ring_n++;
+ pr_info("sema-chan: auto-pinned GR ring h=0x%x rank=%u va=0x%llx -> fb 0x%llx (shadow scan d=0x%llx; entry0 va=0x%llx len=%u put=%u get=%u)\n",
+ ch->h_object, ch->gr_index,
+ ch->gpfifo_va, off,
+ udeltas[ui], hva, hlen, p3,
+ g3);
+ return;
+ }
+ }
+ }
+ }
+
if (!test_and_set_bit(ch->gr_index, &svc_gr_ring_tried)) {
u8 d1[8] = { 0 }, d2[8] = { 0 };
int cap = ch->userd_as ? ch->userd_as : SVC_APERTURE_SYS;