diff options
| -rw-r--r-- | kernel/gsp_sema_service.c | 51 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.h | 6 | ||||
| -rw-r--r-- | kernel/main.c | 19 |
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 |
