From 459384e02bba4eca04fa3eca2365a731a4a7a33a Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Sun, 18 Oct 2026 16:01:10 -0400 Subject: vgsp: stale-replay leg is now strictly non-harmful (r235 second-client death) r235-2 mechanism: at R2's ctx-init one pass fired 8 'stale-replay rewind=1' lines (waited_ms=3491, incl. fresh channels with sub=6 put=1) and set each channel's pin-batch rewind cooldown to +24 s. The rewind is the retry path for a fresh context (its init pushes are decoded before the pins land; the rewind re-decodes them once the translations exist), so disabling it killed R2 exactly like it would every next client (r233 P2+, r235 R2-R4). R1 (working) fired zero tokens. The 3 s window misread a normal init oscillation (rewind replaying a just-consumed entry) as a rewind livelock. - Removed the rewind cooldown entirely: wd_rewind_off_until field, write-back, watchdog clear/set and the svc_handle_map_add skip are gone. The pin-batch rewind is never manipulated by any recovery. - stale-replay now requires SVC_GR_STALE_REPLAY_MS (10 s) of stalled position with consumption happening (a genuine livelock; r225 wedge was 42 s+), keeps its window accumulating until then, and clamps last_get = put at most once per put epoch (wd_epoch_done). - Token updated: '... reason=stale-replay reset=0 clamp=1 ...' (no rewind manipulation; clamp is bookkeeping, a rewind may undo it). Epoch legs (residual/dead-range), stale-entry, newbind window, pending-map/rebuild path, kill-recovery, r220 guard and the m181 rule are unchanged. make kernel green. --- kernel/gsp_sema_service.c | 71 ++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 55482cd..6e37b2f 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -417,7 +417,6 @@ struct svc_channel { u64 wd_put; /* put at the window start */ u64 wd_sub; /* submissions at the window start */ unsigned long wd_since; /* window start (0 = no window) */ - unsigned long wd_rewind_off_until; /* pin-batch rewind cooldown */ bool wd_epoch_done; /* the stale-epoch reset ran for this put */ u32 wd_nocap_put; /* force-replay (no capture) for slots below * this while the stale range is re-walked; 0 = @@ -16572,12 +16571,11 @@ static void svc_userd_sweep(struct nv_vgpu_device *vgpu, struct svc_channel *ch, * forward-only) and never re-capture/re-forward a dead launch. * 2. stale replay: last_get pinned behind put while put == get (the * producer has nothing pending) AND the loop consumed entries during - * the window (submissions moved) - i.e. the rewind is re-opening an - * already-consumed window faster than the loop closes it. The window - * is dropped (last_get = put) and the pin-batch rewind is put on a - * cooldown (wd_rewind_off_until) so the futile retry cannot pin the - * pump; the rewind budget returns later and a translation that lands - * can still retry (bounded duty cycle). + * the window (submissions moved). The cursor is clamped to put once + * per put epoch (bookkeeping only). The pin-batch rewind is NEVER + * touched: r235 proved disabling it kills the next client's + * context-init (its pins land after the first decode; the rewind is + * the retry path). A clamp that a rewind undoes is harmless. * * Nothing here can fire on a green channel: a green channel either moves * put or consumes its first entries within milliseconds (submissions > 0), @@ -16586,6 +16584,15 @@ static void svc_userd_sweep(struct nv_vgpu_device *vgpu, struct svc_channel *ch, * only the rewind re-opening of a consumed window produces. */ #define SVC_GR_STALE_WEDGE_MS 3000u +/* + * STALLFREE r235: the replay/clamp leg needs a MUCH longer stalled window + * than the epoch legs. A fresh client's context-init legitimately shows a + * 3 s position oscillation (rewind replays a just-consumed entry while its + * pins land); treating that as a livelock killed the second client (r235: + * 8 channels classified at waited_ms=3491). Only a position stalled for + * ~10 s with consumption happening is a livelock worth clamping. + */ +#define SVC_GR_STALE_REPLAY_MS 10000u /* * STALLFREE r229/r230: freshness window after a genuinely new channel * binding. Within it, a GR entry whose page is unmapped or whose decode @@ -16613,11 +16620,8 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu, * and the replay cooldown: the next stale region gets its own * recovery. */ - if (ch->wd_put != put) { - if (ch->wd_rewind_off_until) - ch->wd_rewind_off_until = 0; + if (ch->wd_put != put) ch->wd_epoch_done = false; - } /* The forced-replay re-walk is done once the walk catches up. */ if (ch->wd_nocap_put && ch->last_get == put) ch->wd_nocap_put = 0; @@ -16627,7 +16631,7 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu, ch->wd_since = 0; /* progress (or a new position): re-arm */ catchup = (ch->last_get == put); - replay_cand = (!catchup && put == get); + replay_cand = (!catchup && put == get && !ch->wd_epoch_done); /* * Stale epoch: the host caught up (last_get == put) but the ring * still carries a session's residue: put > 1 and the epoch reset @@ -16693,7 +16697,8 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu, * proof this is a producer-pending channel on an unreadable entry, * which the existing grace paths own. */ - fire_replay = replay_cand && ch->submissions != ch->wd_sub; + fire_replay = replay_cand && ch->submissions != ch->wd_sub && + waited >= SVC_GR_STALE_REPLAY_MS; /* * The stalled-entry leg fires only with proof of no progress at all: * nothing was consumed during the window (submissions static), so @@ -16701,7 +16706,12 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu, */ fire_stall = stalled_cand && ch->submissions == ch->wd_sub; if (!residual && !fire_reset && !fire_replay && !fire_stall) { - ch->wd_since = 0; + /* + * Keep an accumulating replay window alive (its evidence needs + * SVC_GR_STALE_REPLAY_MS); anything else restarts. + */ + if (!replay_cand) + ch->wd_since = 0; return; } if (residual || fire_reset) { @@ -16739,12 +16749,19 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu, ch->wd_nocap_put = put; } if (fire_replay) { - /* Drop the rewind-reopened consumed window; cool the rewind. */ + /* + * STALLFREE r235: clamp the stale software cursor to the + * producer position ONCE per put epoch. The pin-batch rewind + * is deliberately NOT touched: disabling it killed every + * second client (r235-2: 8 channels got a 24 s rewind + * cooldown at ctx-init while their pins were landing, so + * their init pushes were never retried). The clamp is + * bookkeeping only and rewind retries stay available. + */ ch->last_get = put; - ch->wd_rewind_off_until = jiffies + - msecs_to_jiffies(8u * SVC_GR_STALE_WEDGE_MS); + ch->wd_epoch_done = true; } - if (residual || fire_reset) + if (residual || fire_reset || fire_replay) ch->wd_epoch_done = true; ch->wd_since = 0; ch->wd_put = put; @@ -16758,7 +16775,7 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu, reason = "stale-entry"; else reason = "stale-epoch"; - 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=%u action=recover reason=%s reset=%d rewind=%d entry=%d cpa=0x%llx rpa=0x%llx\n", + 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=%u action=recover reason=%s reset=%d clamp=%d entry=%d cpa=0x%llx rpa=0x%llx\n", ch->h_object, ch->gpfifo_va, (u32)ch->last_get, put, get, ch->submissions, waited, reason, (fire_reset || fire_stall) ? 1 : 0, @@ -19024,8 +19041,6 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) svc.chan[k].wd_put = ch->wd_put; svc.chan[k].wd_sub = ch->wd_sub; svc.chan[k].wd_since = ch->wd_since; - svc.chan[k].wd_rewind_off_until = - 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; @@ -19498,20 +19513,6 @@ static void svc_handle_map_add(void) if (!ch->valid || !ch->gpfifo_entries) continue; - /* - * STALLFREE r225: a channel under the stale-replay - * watchdog's rewind cooldown is NOT rewound. Without - * this the rewind re-opened the same consumed window - * every batch while the producer had nothing pending, - * pinning last_get and re-walking stale entries - * forever (r225: slots 93..100 of 0x5c000059 for - * 42+ s). The cooldown expires on its own (bounded - * duty cycle) and is cleared by new work, so a - * translation landing later can still retry. - */ - if (ch->wd_rewind_off_until && - time_before(jiffies, ch->wd_rewind_off_until)) - continue; /* * Clamp the rewind at 0: wrapping below zero (get=0 -> * entries - N) makes the pump read ring slots past the -- cgit v1.2.3