summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_rm_emulation.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-17 14:09:04 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-17 14:09:04 -0400
commit1c8ee4942f0377e5304446c691e2e597588d0cac (patch)
treece16161a602b979532b1224034a5ac05d8cc814e /kernel/gsp_rm_emulation.c
parent44d589d032c660a16b78758e6680868b04d5344c (diff)
downloadopen-iov-1c8ee4942f0377e5304446c691e2e597588d0cac.tar.gz
open-iov-1c8ee4942f0377e5304446c691e2e597588d0cac.zip
vgsp: m176 cross-session poison elimination wave - (1) session generation svc_sess_gen bumped by every executed flush; channels+scrubbers stamp it and never inherit per-session learned state (counter_pa/release_pa/rel_done/scrub counts) across a generation (a recycled handle after a flush kept the dead client's write targets: releases landed on - and were forward-only skipped against - the old page while the new client polled its own slot forever: late-boot first-cudaMalloc stall); (2) session flush now clears the 60s targeted-scan failure holds (tr_failed - late clients whose pool page was reachable were still blocked), drops a stale forwarding hold and the captured GR candidate; (3) gsp_rm_emu_reset drops ALL event records regardless of parse state (guest reboot/reload leaves zombies that absorb or suppress new clients' wake-ups) and the FREE retire now requires the record's h_client (hRoot) to match the freed hEvent's owner so a late FREE can never retire a recycled-handle record of a live client; (4) opdef log budget re-armed per session
Diffstat (limited to 'kernel/gsp_rm_emulation.c')
-rw-r--r--kernel/gsp_rm_emulation.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index f203826..8cd82d1 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -3375,11 +3375,19 @@ static void gsp_rm_handle_free(struct gsp_emu_context *ctx, const u8 *elem,
* client's notifier events (hSrcResource 0) linger across runs and the
* fallback wake-up nudge would hit them. Also retire a client's events
* when its root object is freed (hObjOld == hRoot).
+ *
+ * m176: the hEvent match must also match the owning client. Handle
+ * values are recycled across runs, so a late FREE of an old client's
+ * hEvent must never retire a new client's record with the same numeric
+ * handle - the new client's completion wake-up would be lost and it
+ * would wait forever (late-client stall class). hRoot is the freeing
+ * client's own handle in NVOS00_PARAMETERS.
*/
for (i = 0; i < rm->events_n; i++) {
if (!rm->events[i].valid)
continue;
- if (rm->events[i].h_event == hObjOld ||
+ if ((rm->events[i].h_event == hObjOld &&
+ (!hRoot || rm->events[i].h_client == hRoot)) ||
(hObjOld && hObjOld == hRoot &&
rm->events[i].h_client == hRoot)) {
rm->events[i].valid = false;
@@ -3779,8 +3787,32 @@ void gsp_rm_emu_fini(struct gsp_emu_context *ctx)
void gsp_rm_emu_reset(struct gsp_emu_context *ctx)
{
struct gsp_rm_emu *rm = ctx->rm_emu;
+ u32 i, stale;
- if (!rm || !rm->parsed)
+ if (!rm)
+ return;
+
+ /*
+ * m176: a reset means the emulated GSP is gone and every RM client
+ * with it (probe/unload, engine reset). Event records left valid from
+ * the previous session would be posted to with stale
+ * (hClient, hEvent) pairs - the guest RM asserts in CliGetEventInfo
+ * and drops the record - and a recycled hEvent can absorb a wake-up
+ * meant for the new client. Drop them regardless of parse state.
+ */
+ stale = 0;
+ for (i = 0; i < GSPRM_MAX_EVENTS; i++) {
+ if (rm->events[i].valid) {
+ rm->events[i].valid = false;
+ stale++;
+ }
+ }
+ if (stale)
+ nv_vgpu_info(ctx->vgpu,
+ "vgsp-rm: reset dropped %u stale event record(s)",
+ stale);
+
+ if (!rm->parsed)
return;
nv_vgpu_info(ctx->vgpu, "vgsp-rm: reset (rpcs=%llu replied=%llu unknown=%llu)",