summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-08 04:15:24 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-08 04:15:24 -0400
commit5bb2d53ec14f0d802726bc879b994c0286f85415 (patch)
treea6b75f0fd7ab8dc21420041d282ea61049797713 /kernel/gsp_sema_service.c
parent11820d73e35511a8dfe25c65ee2f81970f7ac757 (diff)
downloadopen-iov-5bb2d53ec14f0d802726bc879b994c0286f85415.tar.gz
open-iov-5bb2d53ec14f0d802726bc879b994c0286f85415.zip
vgsp+guest-diag: kcore-truth pin resolver (pool/pushbuffer/channel ring+userd) + GR ring userd-derived candidates
guest_pin_stream.py now resolves translations entirely from guest truth via /proc/kcore + a manual page-table walk (no QMP races): the CE semaphore pool and pushbuffer memory from the UVM rm_mem structures, and each channel's GPFIFO ring + GPPUT from the tracking semaphore's embedding uvm_channel_t (channel_info located by its gpFifoGpuVa value). This removes the watcher pipeline's flakiness on the cudaMalloc stall class (missing pool/pushbuffer pins). gsp_sema_service.c: svc_gr_ring_autopin tries the guest-registered USERD memdesc base as a ring candidate (the fixed FB convention only matches when the guest's VRAM allocator happens to reproduce the old layout), plus an optional (gsp_sema_dbg) one-shot FB scan + raw-word diagnostics when every candidate fails. tools/cuda-ab/p2: self-checking arbitrary-kernel acceptance suite (10 programs: sequential launches, shapes, params, smem/GEMM, streams, malloc churn, printf+error, FMA benchmark, mixed, managed probe) with host oracle expectations and a guest runner.
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c110
1 files changed, 107 insertions, 3 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 9872fac..dc4b7b1 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -7027,6 +7027,7 @@ static void svc_notify_complete(struct nv_vgpu_device *vgpu,
static unsigned long svc_ring_done; /* CE ranks whose ring is pinned */
static unsigned long svc_gr_ring_done; /* GR ranks whose ring is pinned */
+static bool svc_fbs_scan_done; /* one-shot FB entry scan diagnostic */
static u64 svc_gr_ring_base; /* FB offset where GR chunks start */
/* Read and decode the channel's first GPFIFO entry (its first push). */
@@ -7197,6 +7198,58 @@ static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu,
if (!max_ce)
return; /* wait until the CE channels are known */
+ /*
+ * Guest truth first: the channel registration carries the USERD
+ * memdesc base for THIS session's allocation, and the ring sits one
+ * USERD block before it (observed for every GR channel across
+ * boots). The fixed-offset convention below only matches when the
+ * guest's VRAM allocator happens to place the channel allocation at
+ * 0x80000 + 0x20000*CE_count; that layout varies per boot (the
+ * stall class: the convention candidate reads all-zero and the ring
+ * never resolves, so the client's RM event loop waits forever).
+ * Deriving the candidate from the registration removes the guess;
+ * the entry0 + USERD validation stays exactly the same, so a
+ * wrong derived candidate costs a failed probe, not a wrong pin.
+ */
+ if (ch->userd_pa > SVC_GR_USERD_OFF) {
+ static const u64 deltas[] = { SVC_GR_USERD_OFF, 0x1000, 0x0,
+ 0x10000 };
+ int cap = ch->userd_as ? ch->userd_as : SVC_APERTURE_SYS;
+ unsigned int di;
+
+ for (di = 0; di < ARRAY_SIZE(deltas); di++) {
+ u64 cand = ch->userd_pa - deltas[di];
+
+ if (ch->userd_pa <= deltas[di])
+ continue;
+ if (svc_read_ap(vgpu, cand, cap, e, sizeof(e)))
+ continue;
+ memcpy(&e0, e, 4);
+ memcpy(&e1, e + 4, 4);
+ va = ((u64)(e1 & 0xff) << 32) |
+ (u64)(e0 & 0xfffffffc);
+ len = ((e1 >> 10) & 0x1fffff) << 2;
+ if ((va & 0xfffff) || va < SEMA_VA_LO ||
+ va >= SEMA_VA_HI || len < 4 || len > 0x10000)
+ continue;
+ if (svc_userd_probe(vgpu, ch->userd_pa, cap,
+ ch->gpfifo_entries, &put, &get))
+ continue;
+ svc_pin_store(ch->gpfifo_va, cand, cap);
+ svc_lat_store(ch->gpfifo_va, cand, cap);
+ ch->userd_as = cap;
+ ch->userd_ok = true;
+ svc_gr_ring_base = cand;
+ 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 -> pa=0x%llx ap=%d (userd-derived d=0x%llx; entry0 va=0x%llx len=%u put=%u get=%u)\n",
+ ch->h_object, ch->gr_index,
+ ch->gpfifo_va, cand, cap, deltas[di], va,
+ len, put, get);
+ return;
+ }
+ }
+
base = SVC_CE_RING_FB_BASE + SVC_CE_RING_FB_STRIDE * max_ce;
pa = base + SVC_GR_RING_STRIDE * ch->gr_index;
@@ -7284,9 +7337,60 @@ static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu,
}
}
- if (!test_and_set_bit(ch->gr_index, &svc_gr_ring_tried))
- pr_info("sema-chan: GR ring h=0x%x rank=%u not at fb 0x%llx yet (entry e0=0x%x e1=0x%x va=0x%llx len=%u)\n",
- ch->h_object, ch->gr_index, pa, e0, e1, va, len);
+ 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;
+ u64 w1 = 0, w2 = 0;
+ u32 p2 = 0, g2 = 0;
+ int prc;
+
+ if (ch->userd_pa > SVC_GR_USERD_OFF &&
+ !svc_read_ap(vgpu, ch->userd_pa - SVC_GR_USERD_OFF, cap,
+ d1, sizeof(d1)))
+ memcpy(&w1, d1, 8);
+ if (ch->userd_pa &&
+ !svc_read_ap(vgpu, ch->userd_pa, cap, d2, sizeof(d2)))
+ memcpy(&w2, d2, 8);
+ prc = ch->userd_pa ?
+ svc_userd_probe(vgpu, ch->userd_pa, cap,
+ ch->gpfifo_entries, &p2, &g2) : -1;
+ pr_info("sema-chan: GR ring h=0x%x rank=%u not at fb 0x%llx yet (e0=0x%x e1=0x%x va=0x%llx len=%u); userd 0x%llx ap=%d w@u-0x2000=0x%llx w@u=0x%llx probe rc=%d put=%u get=%u\n",
+ ch->h_object, ch->gr_index, pa, e0, e1, va, len,
+ ch->userd_pa, cap, w1, w2, prc, p2, g2);
+
+ /* One-shot content scan of the emulated VRAM for a GPFIFO
+ * entry0-shaped word (1 MB aligned push VA, sane length). The
+ * client's ring allocation offset varies per boot; the scan
+ * names the real location for the fix. */
+ if (gsp_sema_dbg && vgpu->bars[1].vaddr && vgpu->bars[1].size &&
+ !svc_fbs_scan_done) {
+ u64 lim = min_t(u64, vgpu->bars[1].size, 0x20000000ULL);
+ u64 off;
+ int hits = 0;
+
+ svc_fbs_scan_done = true;
+ for (off = 0; off + 8 <= lim && hits < 40; off += 8) {
+ u32 h0, h1;
+ u64 hva;
+ u32 hlen;
+
+ memcpy(&h0, vgpu->bars[1].vaddr + off, 4);
+ memcpy(&h1, vgpu->bars[1].vaddr + 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;
+ pr_info("sema-chan: fbs scan hit off=0x%llx e0=0x%x e1=0x%x va=0x%llx len=%u\n",
+ off, h0, h1, hva, hlen);
+ hits++;
+ }
+ pr_info("sema-chan: fbs scan done h=0x%x hits=%d (lim 0x%llx)\n",
+ ch->h_object, hits, lim);
+ }
+ }
}
static void svc_ring_autopin(struct nv_vgpu_device *vgpu,