diff options
| -rw-r--r-- | kernel/gsp_sema_service.c | 76 |
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); |
