summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-27 10:26:38 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-27 10:26:38 -0400
commitbd1f27476fc11dc0bc45eb1aa666e352f34a0168 (patch)
treec6542466394f637a077d8e89f4d5f12b3cc5825f /kernel
parentcb1653d62f521943497e5705803f461ab7041dda (diff)
downloadopen-iov-bd1f27476fc11dc0bc45eb1aa666e352f34a0168.tar.gz
open-iov-bd1f27476fc11dc0bc45eb1aa666e352f34a0168.zip
vgsp: client-session boundary fixes - WD ring scan gate + forced session flush
Two changes from the r839/r840 multi-client forensics (session 147): 1. The guest-RAM content scan for a GR ring must not run for the kernel RC-watchdog channel (h=0x31415900). Its ring is a plain kernel allocation always resolvable through the driver-published VAS walk; on r840 the walk lost a registration race, the scan latched a foreign garbage page, and the bad latch poisoned the driver's DMA test ('Failed to initialize DMA', Xorg died). Gated, the walk retries per pass; r841 Xorg#1 passes DMA (DMAFAIL=0) where r840 failed. 2. sema_force_flush module parameter + gsp_sema_service_sess_flush_force(): execute the ISSUE-0002 client-session flush even with live channels. The channel-close trigger never fires on real boots (driver-global channels stay valid), so later client sessions inherited stale discovery state. Verified on r841: flush executes mid-boot, Xorg survives it and re-registers its channels. Remaining wall (addendum 9): GR client channels' pushbuffer reads return all-zero through the trusted translation (va=0x4000000-class, src=4), so first entries never complete and GL clients never render.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c51
-rw-r--r--kernel/gsp_sema_service.h6
-rw-r--r--kernel/main.c19
3 files changed, 73 insertions, 3 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index f6ad3b2..9c72b4b 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -678,6 +678,9 @@ static u32 svc_ring_n;
*/
static u8 svc_sess_flush;
static u8 svc_guest_reset_req; /* m177: guest RM reload; wiped on svc thread */
+static u8 svc_sess_flush_forced; /* execute the next flush past the live-channel skip
+ * (ISSUE-0002 client-session boundary aid; see
+ * gsp_sema_service_sess_flush_force) */
static u8 svc_sess_active; /* a channel of a session has registered (until flush) */
static u32 svc_sess_gen; /* m176: bumped by every executed session flush;
* stamps channels/scrubbers so per-session learned
@@ -13415,6 +13418,7 @@ static void svc_session_flush(void)
*/
{
bool live = false;
+ bool forced = READ_ONCE(svc_sess_flush_forced);
spin_lock_irqsave(&svc.chan_lock, flags);
for (i = 0; i < SVC_MAX_CHANNELS; i++)
@@ -13423,10 +13427,15 @@ static void svc_session_flush(void)
break;
}
spin_unlock_irqrestore(&svc.chan_lock, flags);
- if (live) {
+ if (live && !forced) {
pr_info("sema-svc: session flush skipped: live channel(s) present (deferred flush raced a new session registration)\n");
return;
}
+ if (forced) {
+ svc_sess_flush_forced = 0;
+ pr_info("sema-svc: session flush (forced) executing with live=%d channel(s)\n",
+ live);
+ }
}
svc_gr_diag_reset(); /* m150: per-session diagnostic budgets */
@@ -17532,8 +17541,24 @@ static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu,
* entry and pushbuffer reads resolve. Sliced so the service thread
* stays responsive; gives up per channel after
* SVC_GR_RAM_PASS_MAX slices.
- */
- if (ch->gr_ram_passes < SVC_GR_RAM_PASS_MAX &&
+ *
+ * SESSION 147 (r840 evidence): the scan must NOT run for the kernel
+ * RC-watchdog channel (h=0x31415900). Its ring is a plain kernel
+ * allocation whose VA is always resolvable through the driver-
+ * published VAS walk - the walk is the correct, deterministic
+ * source. On r840 the walk lost a registration race, the scan ran
+ * first and latched a FOREIGN page (pa=0x101cc3000, garbage
+ * entries: raw=0xffff88f10403e000), and the bad latch poisoned
+ * every later entry/push read: the driver's DMA test never saw its
+ * push complete and Xorg died with "Failed to initialize DMA"
+ * (the same boot passed on r835/836/838 where the trusted walk
+ * won the race). Gating the scan keeps the per-pass walk retry
+ * alive for the watchdog; the walk landing late is indistinguishable
+ * from the r838 flow, and never landing is no worse than a poisoned
+ * latch.
+ */
+ if (ch->h_object != 0x31415900u &&
+ ch->gr_ram_passes < SVC_GR_RAM_PASS_MAX &&
!test_bit(ch->gr_index, &svc_gr_ring_done)) {
u64 hit_pa = 0;
@@ -30684,6 +30709,26 @@ static void svc_stall_watch_check(void)
svc_force_consume = 4;
}
+/*
+ * ISSUE-0002 client-session boundary aid: force a session flush that
+ * executes even while channels are live. The channel-close trigger only
+ * fires when the table empties, which never happens on a guest where the
+ * driver-global kernel channels (RC watchdog 0x31415900, the tiny notifier
+ * channel) stay valid; later client sessions then inherit the previous
+ * session's map/pin/pool discovery state and wedge (false translations ->
+ * failed rescues -> driver DMA-init timeout). Raised through the
+ * sema_force_flush module parameter so the boundary can be tested before
+ * wiring automatic detection.
+ */
+void gsp_sema_service_sess_flush_force(void)
+{
+ WRITE_ONCE(svc_sess_flush_forced, 1);
+ WRITE_ONCE(svc_sess_flush, 1);
+ if (READ_ONCE(svc.task))
+ wake_up_process(svc.task);
+ pr_info("sema-svc: forced session flush requested\n");
+}
+
static int svc_thread(void *arg)
{
struct nv_vgpu_device *vgpus[SVC_MAX_GUESTS];
diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h
index 63c7f82..2184826 100644
--- a/kernel/gsp_sema_service.h
+++ b/kernel/gsp_sema_service.h
@@ -120,6 +120,12 @@ void gsp_sema_service_vaspace_candidate_add(u32 h_vaspace, u64 pdb,
* session flushes keep that state - see svc_session_flush. */
void gsp_sema_service_guest_reset(void);
+/*
+ * ISSUE-0002 aid: force a client-session flush that executes even while
+ * channels are live (see addendum 8 and the sema_force_flush parameter).
+ */
+void gsp_sema_service_sess_flush_force(void);
+
int gsp_sema_service_start(void);
void gsp_sema_service_stop(void);
int gsp_sema_service_probe(u64 gpu_va, u32 count);
diff --git a/kernel/main.c b/kernel/main.c
index 7016647..a034b44 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -2554,6 +2554,25 @@ module_param_cb(sema_probe, &nv_vgpu_sema_probe_ops, NULL, 0200);
MODULE_PARM_DESC(sema_probe, "Dump sema-service map + slot values for a GPU VA");
/*
+ * ISSUE-0002 aid: force a client-session flush past the live-channel skip.
+ * Write anything (echo 1 > .../parameters/sema_force_flush).
+ */
+static int nv_vgpu_sema_force_flush_set(const char *val,
+ const struct kernel_param *kp)
+{
+ gsp_sema_service_sess_flush_force();
+ return 0;
+}
+
+static const struct kernel_param_ops nv_vgpu_sema_force_flush_ops = {
+ .set = nv_vgpu_sema_force_flush_set,
+};
+
+module_param_cb(sema_force_flush, &nv_vgpu_sema_force_flush_ops, NULL, 0200);
+MODULE_PARM_DESC(sema_force_flush,
+ "Force a client-session flush even with live channels (ISSUE-0002 aid)");
+
+/*
* Register the guest PMA scrubber channel buffer words (finish payload PA,
* host-semaphore PA) the guest scanner resolved:
* echo 0x11a8ff004,0x11a8ff000 > .../parameters/sema_scrubbuf_add