summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-18 15:12:04 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-18 15:12:27 -0400
commit57af76cd9cbe73a6406681bd8a51258849b98384 (patch)
tree43eadf0da74e8329fa75ce607ba5dde0d83eb2f7 /kernel/gsp_sema_service.c
parentb7c1cff5f290ae19ceca47f4d0bb9024eb45146c (diff)
downloadopen-iov-57af76cd9cbe73a6406681bd8a51258849b98384.tar.gz
open-iov-57af76cd9cbe73a6406681bd8a51258849b98384.zip
vgsp: channel-reuse reconciliation + hint-flood stop (GR-STALL-stale-entry-chanswitch)
r229a evidence: victory_mail OK -> ctaid_probe attempt 1 printed DEVICE and never completed (killed at 50 s); attempt 2 (fresh context) worked. The retained window shows mail's teardown + session flush (gen 3) then, for the whole first-attempt window, no channel registration and only the host 'completion hint rc=-2' flood (~0.5 s cadence, window reopened by the completion-apply sites). No GR lines, no stale-* lines: the first launch never reached the sema walk for the new binding. - svc_thread hint: on rc == -2 (no event context to post to) stop reopening svc.post_hint_until; the next real completion reopens it. The flood was pure noise and obscured the real state. - Channel-reuse reconciliation: svc_chan_registration marks a genuinely new binding (!same_gen) with wd_chanswitch; the channel's first pump pass drops every opdef slot bound to that handle (a dead context's withheld sets must not ride the reused channel - the r228 opdef-hold class) and, when the ring already carries content (put > 1), logs 'GR-STALL-stale-wedge ... reason=stale-entry-chanswitch'. Captures stay enabled: the fresh client's own entries may already be at slot 0, and suppressing them would lose exactly the first launch this protects; a stale launch re-walk stays bounded by gsp_phys_gr_wait_max_ms and the m181 put-drop recovery. r220 hold guard and the m181 arm rule untouched. Note: the phase2 witness for r229 was not readable at commit time (/tmp/opencode/witness-r229-phase2.log absent); r229a is boot-side and post-flush, so the attempt-1 window shows the guest sent no RM/channel traffic for ~9.5 s - the reconciliation removes the host-side reused- handle state classes; r230 will show whether the first-attempt launch now reaches the walk. make kernel green. (cherry picked from commit 21eb5bb0582aaa2409601a1a1466f7bc72841647)
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index e57bcac..19b2d32 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -422,6 +422,11 @@ struct svc_channel {
u32 wd_nocap_put; /* force-replay (no capture) for slots below
* this while the stale range is re-walked; 0 =
* none */
+ bool wd_chanswitch; /* STALLFREE r229: registered; first pump
+ * pass must reconcile the binding before the
+ * walk (drop dead opdef slots, treat any
+ * pre-existing ring content as another
+ * context's: release-only re-walk) */
};
/*
@@ -1308,6 +1313,18 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc)
ch->gr_rehold_idx = ~0u;
ch->gr_nocap_idx = ~0u; /* m164: no no-capture window armed */
ch->session_gen = svc_sess_gen; /* m176 */
+ /*
+ * STALLFREE r229: a genuinely new binding - a fresh channel or
+ * a same-handle rebinding across a session/context boundary
+ * (!same_gen) - must reconcile on its first pump pass: drop
+ * opdef slots a dead context left under this handle and treat
+ * any pre-existing ring content as that context's
+ * (release-only re-walk, no captures), so the first launch on
+ * a reused channel cannot be silently consumed from another
+ * context's bytes. A same-generation RM re-issue preserves
+ * state deliberately (m148/m176) and is not reconciled.
+ */
+ ch->wd_chanswitch = !same_gen;
if (same_gen)
bitmap_copy(ch->rel_done, keep_rel_done,
SVC_GPFIFO_MAX_BITS);
@@ -13348,6 +13365,26 @@ static void svc_opdef_drop_gone(struct nv_vgpu_device *vgpu,
}
}
+/*
+ * STALLFREE r229: drop every opdef slot bound to one channel handle. A
+ * context switch/teardown invalidates the handle's withheld sets - their
+ * waiters are gone and the releases must not ride the reused channel (the
+ * session flush already clears them at a session boundary; this covers a
+ * same-handle rebinding that races the flush). Counted as a LOSS when the
+ * slot still held undelivered releases.
+ */
+static void svc_opdef_drop_channel(struct nv_vgpu_device *vgpu, u32 h_object)
+{
+ int i;
+
+ for (i = 0; i < SVC_OPDEF_SLOTS; i++) {
+ struct svc_opdef_ent *e = &svc_opdef[i];
+
+ if (e->active && e->vgpu == vgpu && e->h_object == h_object)
+ svc_opdef_drop_counted(e);
+ }
+}
+
static void svc_opdef_reset_all(void)
{
int i;
@@ -17034,6 +17071,34 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc_gr_stale_wedge_check(vgpu, ch, put, get);
/*
+ * STALLFREE r229: first-use reconciliation after a genuinely
+ * new binding (see svc_chan_registration). The rebinding's
+ * ring cursor starts at 0 (fresh sequence); drop the dead
+ * context's opdef slots under this handle (their waiters are
+ * gone and the sets must not ride the reused channel, the
+ * r228 opdef-hold class), and when the ring already carries
+ * content (put > 1) log the reconcile so the transition is
+ * visible. Captures stay enabled: the fresh client's own
+ * entries may already be at slot 0.., and suppressing them
+ * would lose exactly the first launch this must protect; a
+ * stale launch re-walk is bounded by the submit budget and
+ * the m181 put-drop recovery (same precedent).
+ */
+ if (ch->wd_chanswitch) {
+ ch->wd_chanswitch = false;
+ svc_opdef_drop_channel(vgpu, ch->h_object);
+ if (put > 1) {
+ svc.gr_stale_wedge++;
+ pr_warn_ratelimited("vgsp-gr: GR-STALL-stale-wedge h=0x%x va=0x%llx last=%u put=%u get=%u sub=%llu waited_ms=0 action=recover reason=stale-entry-chanswitch reset=0 rewind=0 entry=0 cpa=0x%llx rpa=0x%llx\n",
+ ch->h_object, ch->gpfifo_va,
+ (u32)ch->last_get, put, get,
+ ch->submissions,
+ ch->counter_pa,
+ ch->release_pa);
+ }
+ }
+
+ /*
* m136 (SA-STALL M2): liveness watchdog for a held CE entry.
* When this channel's entry loop is not re-entered (early
* continue paths above, or no fresh pushes), a deferred entry
@@ -18802,6 +18867,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
ch->wd_rewind_off_until;
svc.chan[k].wd_epoch_done = ch->wd_epoch_done;
svc.chan[k].wd_nocap_put = ch->wd_nocap_put;
+ svc.chan[k].wd_chanswitch = ch->wd_chanswitch;
svc.chan[k].pushpg_va = ch->pushpg_va;
svc.chan[k].pushpg_n = ch->pushpg_n;
svc.chan[k].content_max = ch->content_max;
@@ -19778,6 +19844,16 @@ static int svc_thread(void *arg)
svc.last_hint = jiffies;
rc = gsp_rm_post_all_events(vgpu);
+ /*
+ * STALLFREE r229: -2 means there is no event
+ * context to post to (a client before its first
+ * registration, or a torn-down one). Stop
+ * reopening the hint window then - the flood is
+ * pure noise and hides the real state; the next
+ * completion reopens it.
+ */
+ if (rc == -2)
+ svc.post_hint_until = 0;
if (gsp_sema_dbg)
pr_info_ratelimited("sema-svc: completion hint rc=%d\n",
rc);