From c1350b040f740f3aeb426bf8407ab930f5e87c28 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 19 Oct 2026 07:57:32 -0400 Subject: vgsp: newbind holds are residual-only and short (r237 T2 3 s GP_GET delay) r237-2: T2's GR channel carried T1's residual put=115; my 3 s empty-decode hold delayed the host's GP_GET during the residual walk, and the guest unwound at binding+3.46 s (zeroed PROMOTE_CTX, then full FREE) - exactly when the host finally consumed the residual. The guest's ctx-init patience is ~3 s, so the hold must never delay the walk that long. - New SVC_GR_NEWBIND_HOLD_MS 1200u and per-channel wd_newbind_hold_until: the hold windows (empty-decode and unmapped entry) now apply only while it is fresh (<1.2 s; the rebuild lands in ~0.8 s) and only when put == get (residual context, no producer work pending). Any pending producer work is walked without delay, so GP_GET always advances promptly. - wd_newbind_until (3 s) still governs retry eligibility; the opdef drop, chanswitch log, pending-map/rebuild path are unchanged. make kernel green. --- kernel/gsp_sema_service.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'kernel/gsp_sema_service.c') diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 6e37b2f..0520c4f 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -425,6 +425,9 @@ struct svc_channel { * must reconcile the binding before the walk * (drop dead opdef slots whose since predates * the binding; log the transition) */ + unsigned long wd_newbind_hold_until; /* short hold window inside + * wd_newbind_until (residual-only, + * put==get; never delays fresh work) */ unsigned long wd_newbind_until; /* STALLFREE: freshness window of a * new binding; inside it an * unmapped/undecoded GR entry is held @@ -16604,6 +16607,15 @@ static void svc_userd_sweep(struct nv_vgpu_device *vgpu, struct svc_channel *ch, * window of extra latency on first contact. */ #define SVC_GR_NEWBIND_MS 3000u +/* + * STALLFREE r237: the HOLD part of the window must be shorter than the + * window itself. r237-2: the 3 s hold on T2's residual ring delayed its + * GP_GET past the guest's ~3 s ctx-init patience (T2 unwound with a + * zeroed PROMOTE_CTX at binding+3.46 s, exactly when the host finally + * consumed the residual). The guest needs GP_GET to advance promptly; + * the rebuild lands in ~0.8 s, so 1.2 s is enough for one attempt. + */ +#define SVC_GR_NEWBIND_HOLD_MS 1200u static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu, struct svc_channel *ch, u32 put, u32 get) @@ -17195,6 +17207,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) svc_opdef_drop_channel(vgpu, ch->h_object, jiffies); ch->wd_newbind_until = jiffies + msecs_to_jiffies(SVC_GR_NEWBIND_MS); + ch->wd_newbind_hold_until = jiffies + + msecs_to_jiffies(SVC_GR_NEWBIND_HOLD_MS); /* * Bounded proof (r234 asks): the window was armed for * THIS binding; if a later stall shows no such line, @@ -17719,9 +17733,10 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) !entry_replay && svc_rel_count == rel_n_iter && svc_gr_qmd_seen == 0 && - ch->wd_newbind_until && + put == get && + ch->wd_newbind_hold_until && time_before(jiffies, - ch->wd_newbind_until)) { + ch->wd_newbind_hold_until)) { if (!ch->defer_since) ch->defer_since = jiffies; @@ -18805,9 +18820,10 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) * the rebuild caught up). */ if (!ch->engine_type && - ch->wd_newbind_until && + put == get && + ch->wd_newbind_hold_until && time_before(jiffies, - ch->wd_newbind_until)) { + ch->wd_newbind_hold_until)) { svc.rebuild_now = true; if (svc.gr_pending_map < 16) { svc.gr_pending_map++; @@ -19045,6 +19061,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) svc.chan[k].wd_nocap_put = ch->wd_nocap_put; svc.chan[k].wd_chanswitch = ch->wd_chanswitch; svc.chan[k].wd_newbind_until = ch->wd_newbind_until; + svc.chan[k].wd_newbind_hold_until = + ch->wd_newbind_hold_until; svc.chan[k].pushpg_va = ch->pushpg_va; svc.chan[k].pushpg_n = ch->pushpg_n; svc.chan[k].content_max = ch->content_max; -- cgit v1.2.3