summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-31 18:06:14 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-31 18:06:14 -0400
commit4c86ccffd3fe38be344bc75d97bedf54c00a648a (patch)
tree4936d32139899da2155b35851ca3de2cb3b48427
parent69b59a0d67d12e4767736a423bd307feeffef016 (diff)
downloadopen-iov-4c86ccffd3fe38be344bc75d97bedf54c00a648a.tar.gz
open-iov-4c86ccffd3fe38be344bc75d97bedf54c00a648a.zip
vgsp: channel-registered logs vas=%x vas_known (0xbeef0100 hVASpace NULL = attach-to-TSG; 0xbeef0101/102 vas=0xbeef0300 known) + svc_gr_ring_stale_heal (once/s stale-pin self-heal via client VAS walk, GR ring re-pin) - r1156 held push was a PHANTOM (e0 0x3e4ccccd=0.2f+e1 0x81e40e00 decode to 123916; float data from reused ring page) - r1157 pipeline real (9000 entry decodes, 1499 launches, chunked 1429 words, prelude gen=4 words=773); store wall = missing MME macro carrier (real 60216B push 0x4001004 head zeros, no parseable content in any client mapping); next: post-re-registration USERD resolution (channel churns every ~12s: RAM scan found no candidate) - SESSION 153 r1157
-rw-r--r--kernel/gsp_sema_service.c143
1 files changed, 141 insertions, 2 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index d79bfc5..d856241 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -1999,6 +1999,31 @@ static void svc_chan_rearm_rank(struct svc_channel *ch)
}
/*
+ * SESSION 153-CONTINUED-75: does the service hold a page directory for this
+ * VA-space handle? The channel-registration log uses this to name the
+ * discovery gap on the line itself (a nonzero channel hVASpace absent from
+ * svc.vas[] is exactly the "undiscovered VAS" condition the CONT-74
+ * investigation looked for by hand).
+ */
+static bool svc_vaspace_known(u32 h_vaspace)
+{
+ unsigned long flags;
+ bool found = false;
+ int i;
+
+ if (!h_vaspace)
+ return false;
+ spin_lock_irqsave(&svc.vas_lock, flags);
+ for (i = 0; i < SVC_MAX_VASPACES; i++)
+ if (svc.vas[i].valid && svc.vas[i].h_vaspace == h_vaspace) {
+ found = true;
+ break;
+ }
+ spin_unlock_irqrestore(&svc.vas_lock, flags);
+ return found;
+}
+
+/*
* Register a guest channel. Called from the GSP-RM emulation when the guest
* driver allocates a channel (the allocation carries the GPFIFO GPU VA, its
* entry count and the guest-physical USERD/instance blocks), and dropped when
@@ -2281,10 +2306,22 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc)
desc->gpfifo_va, desc->userd_pa);
}
scrub_done:
- pr_info("sema-svc: channel 0x%x registered gpfifo=0x%llx entries=%u userd=0x%llx eng=%u cid=%u notif=0x%llx\n",
+ /*
+ * SESSION 153-CONTINUED-75: name the channel's declared VA
+ * space and whether the service has a page directory for it.
+ * hVASpace==0 is the driver's "attach to the TSG address
+ * space" (nv_gpu_ops.c: "If zero then it will attach to the
+ * TSG address space"), which is why the GR channel's
+ * low-aperture ring/push VAs resolve through the TSG/client
+ * VAS published by its CE siblings, not through a handle of
+ * its own. A nonzero handle that never appears in svc.vas[]
+ * names the discovery gap directly.
+ */
+ pr_info("sema-svc: channel 0x%x registered gpfifo=0x%llx entries=%u userd=0x%llx eng=%u cid=%u notif=0x%llx vas=0x%x vas_known=%d\n",
desc->h_object, desc->gpfifo_va, desc->gpfifo_entries,
desc->userd_pa, desc->engine_type, desc->cid,
- desc->notifier_pa);
+ desc->notifier_pa, desc->h_vaspace,
+ svc_vaspace_known(desc->h_vaspace));
}
else
pr_warn_ratelimited("sema-svc: channel 0x%x dropped: channel table full (%d)\n",
@@ -23448,6 +23485,101 @@ static void svc_kick_ring_revalidate(struct nv_vgpu_device *vgpu,
}
/*
+ * SESSION 153-CONTINUED-75: GR ring stale-pin self-heal.
+ *
+ * The GR ring pin can outlive the page it names. The client churns its
+ * channels every ~12 s (fence timeouts), frees the ring allocation, and the
+ * driver's allocator reuses the PA. Live evidence (r1156): the beef ring
+ * pin 0x238041000 later held glxgears vertex/matrix floats and every
+ * "entry" the pump decoded from it was float data - the phantom held push
+ * va=0x3e4ccccc len=123916 is exactly the float pair (0x3e4ccccd = 0.2f,
+ * 0x81e40e00). A stale pin shadows the client's own page tables in
+ * svc_lookup, so the channel runs on phantom entries and never retires.
+ *
+ * Once per second, when the current translation's entry0 no longer decodes
+ * as a ring entry (dead, zeroed or float junk), ask the client's own VAS
+ * walk for the ring VA. If the walk resolves a DIFFERENT page whose entry0
+ * DOES decode through the same window/length gate every adoption path uses,
+ * re-pin to that page and log it. With no walk, or a walk page that also
+ * fails the gate, nothing is touched: the heal can only replace a
+ * provably-dead translation with a provably-plausible one.
+ */
+static unsigned long svc_gr_heal_at[32];
+static u32 svc_gr_heal_log;
+static u64 svc_gr_heal_n;
+
+static bool svc_gr_entry_plausible(const struct svc_channel *ch, u32 e0,
+ u32 e1)
+{
+ u64 eva = ((u64)(e1 & 0xff) << 32) | (u64)(e0 & 0xfffffffc);
+ u32 elen = ((e1 >> 10) & 0x1fffff) << 2;
+
+ if ((eva & 0xfffff) || elen < 4 || elen > 0x10000)
+ return false;
+ if ((eva < SEMA_VA_LO || eva >= SEMA_VA_HI) &&
+ !svc_gr_entry_win_ok(ch->gpfifo_va, eva))
+ return false;
+ return true;
+}
+
+static void svc_gr_ring_stale_heal(struct nv_vgpu_device *vgpu,
+ struct svc_channel *ch)
+{
+ u8 e[SVC_GPFIFO_ENTRY_SIZE];
+ u32 e0 = 0, e1 = 0;
+ u64 wpa = 0, cpa = 0;
+ int wap = SVC_APERTURE_SYS, cap = SVC_APERTURE_SYS;
+
+ if (!ch->gpfifo_va || ch->engine_type || ch->gr_index >= 32)
+ return;
+ if (!time_after(jiffies, svc_gr_heal_at[ch->gr_index]))
+ return;
+ svc_gr_heal_at[ch->gr_index] = jiffies + msecs_to_jiffies(1000);
+
+ /*
+ * Entry0 through the CURRENT translation (the pin shadows the walk in
+ * svc_lookup). An unreadable read gets the walk check too - the pin
+ * may name freed memory the read path rejects.
+ */
+ if (!svc_read_va(vgpu, ch->gpfifo_va, e, sizeof(e))) {
+ memcpy(&e0, e, 4);
+ memcpy(&e1, e + 4, 4);
+ if (svc_gr_entry_plausible(ch, e0, e1))
+ return; /* live ring; nothing to do */
+ } else {
+ e0 = 0;
+ e1 = 0;
+ }
+
+ if (svc_pin_lookup_any(ch->gpfifo_va, &cpa, &cap))
+ cpa = 0;
+
+ /* The client's own page tables answer the ring VA right now? */
+ if (svc_walk_vaspaces(vgpu, ch->gpfifo_va & ~(u64)(SEMA_PAGE_SIZE - 1),
+ &wpa, &wap))
+ return; /* no walk: no verdict, leave the pin alone */
+ if (cpa && (wpa & ~0xfffULL) == (cpa & ~0xfffULL))
+ return; /* walk agrees with the implausible pin: dead either way */
+ if (svc_read_ap(vgpu, wpa, wap, e, sizeof(e)))
+ return;
+ memcpy(&e0, e, 4);
+ memcpy(&e1, e + 4, 4);
+ if (!svc_gr_entry_plausible(ch, e0, e1))
+ return; /* the walk page is not a live ring either */
+
+ svc_pin_store(ch->gpfifo_va, wpa, wap);
+ svc_lat_store(ch->gpfifo_va, wpa, wap);
+ svc_gr_heal_n++;
+ if (svc_gr_heal_log < 16) {
+ svc_gr_heal_log++;
+ pr_info("sema-chan: GR ring re-pin h=0x%x va=0x%llx -> pa=0x%llx ap=%d (stale translation 0x%llx no longer decodes; walk entry0 va=0x%llx len=%u)\n",
+ ch->h_object, ch->gpfifo_va, wpa, wap, cpa,
+ ((u64)(e1 & 0xff) << 32) | (u64)(e0 & 0xfffffffc),
+ ((e1 >> 10) & 0x1fffff) << 2);
+ }
+}
+
+/*
* r912 (M-GL1.2): guest-RAM USERD shape scan for a GR channel whose ring
* was content-validated in guest RAM (gr_ram_ring; svc_gr_ram_ring_scan).
* Such a client's USERD is a system-memory object like its ring, so the
@@ -35497,6 +35629,13 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
continue;
svc_ring_autopin(vgpu, ch);
+ /*
+ * SESSION 153-CONTINUED-75: heal a GR ring whose translation
+ * has gone stale (the client's churn frees the ring page and
+ * the allocator reuses it for data; the stale pin then feeds
+ * the pump phantom entries - see svc_gr_ring_stale_heal).
+ */
+ svc_gr_ring_stale_heal(vgpu, ch);
rrc = svc_lookup(vgpu, ch->gpfifo_va, &ring_pa, &ring_ap);