From 3cf03c0665e4fa2eb5808bb25b3fe5165fe1c3c4 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 19 Oct 2026 19:23:53 -0400 Subject: vgsp: sync gsp_sema_service.c to fail4 after cherry-pick conflict (wd_rewind_off_until struct member repair) --- kernel/gsp_sema_service.c | 514 ++++++++++------------------------------------ 1 file changed, 113 insertions(+), 401 deletions(-) (limited to 'kernel/gsp_sema_service.c') diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 09b8ee4..1b86945 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -421,22 +421,7 @@ 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) */ - 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 = - * none */ - bool wd_chanswitch; /* STALLFREE: registered; first pump pass - * 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 - * (not silently consumed) and an - * immediate rebuild is requested */ + unsigned long wd_rewind_off_until; /* pin-batch rewind cooldown */ }; /* @@ -1038,19 +1023,6 @@ struct sema_svc { * stale-replay wedge watchdog (zero on a green run). */ u64 gr_stale_wedge; - /* - * STALLFREE r229/r230: set by the pump when a new binding's GR entry - * is unmapped/empty; the service loop consumes it by running - * svc_rebuild() before the next pump pass, so the page translations - * land within ~1 s and the pending entry re-evaluates. - */ - bool rebuild_now; - u32 gr_pending_map; /* GR-STALL-pending-map lines - * emitted (bounded proof) */ - u32 gr_newbind_log; /* GR-STALL-newbind window-armed - * lines emitted (bounded proof) */ - u32 gr_rebuild_log; /* GR-STALL-rebuild consumption - * lines emitted (bounded proof) */ u64 fwd_gr_hold_exp; /* GRFIX FIX1: data-stalled holds * that reached the hard bound and * were consumed with the software @@ -1839,7 +1811,14 @@ static int svc_gmmu_walk(struct nv_vgpu_device *vgpu, u64 pdb, u32 entries, return -ENOENT; } - /* PD0: one dual entry per index (big half then small half). */ + /* + * PD0: one dual entry per index (big half then small half). + * Geometry per the driver's own GMMU format (gp10x family): + * PD3 [48:47], PD2 [46:38], PD1 [37:29], PD0 [28:21], PT + * [20:12]. PD0 is 8 bits - an earlier 0x1ff experiment here was + * reverted; the observed +2 MB client-page phase is NOT a PD0 + * index error. + */ idx = (va >> 21) & 0xff; if (svc_read_ap(vgpu, table + 16 * idx, tap == SVC_APERTURE_FB ? SVC_APERTURE_FB @@ -3056,6 +3035,16 @@ static u32 svc_pool_pa_n; static u32 svc_pool_pa_next; static u64 svc_pool_pa_logged[SVC_POOL_PA_LOG_MAX]; static u32 svc_pool_pa_logged_n; +/* + * fail4: the completion-hint window was 10 s. It outlived short-lived + * clients: after a client freed its RM events the window kept re-posting + * hint events every 0.5 s, and a post already queued in the status ring + * could be read after the guest's own free processing - the guest ISR + * then ran a freed RC callback and the guest panicked in interrupt + * (rm_run_rc_callback+0x0). 1.5 s still covers a waiter that arrives + * after the edge while shrinking the post-free exposure ~7x. + */ +#define SVC_POST_HINT_MS 1500 static u64 svc_pool_pa_miss_log; static u32 svc_pool_pa_hit_log; static u32 svc_pool_wr_log; @@ -6706,7 +6695,7 @@ static void svc_counter_release_apply(struct nv_vgpu_device *vgpu, u32 h, wrc = svc_sem_write(vgpu, h, sem_va, payload); if (!wrc) { svc.releases_applied++; - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); if (gsp_sema_dbg && svc.counter_rel_dbg < 256) { svc.counter_rel_dbg++; pr_info("sema-chan: rel-apply h=0x%x va=0x%llx pay=%u cur=%u -> pool rescue\n", @@ -6791,7 +6780,7 @@ static void svc_counter_release_apply(struct nv_vgpu_device *vgpu, u32 h, svc.releases_applied++; svc.counter_rel_applied++; svc.gr_rel_applied++; - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); if (gsp_sema_dbg && svc.counter_rel_dbg < 256) { svc.counter_rel_dbg++; pr_info("sema-chan: rel-apply h=0x%x pa=0x%llx pay=%u cur=%u -> written\n", @@ -6874,7 +6863,7 @@ static void svc_counter_flush_pending(struct nv_vgpu_device *vgpu, svc.releases_applied++; svc.counter_rel_applied++; svc.gr_rel_applied++; - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); if (gsp_sema_dbg && svc.counter_rel_dbg < 256) { svc.counter_rel_dbg++; pr_info("sema-chan: rel-flush h=0x%x pa=0x%llx pay=%u cur=%u -> written\n", @@ -7245,7 +7234,7 @@ static bool svc_rel_apply_906f(struct nv_vgpu_device *vgpu, cur = (op == HOST_SEM_OP_REDUCTION) ? cur + payload : payload; if (!svc_sem_write(vgpu, ch->h_object, va, cur)) { svc.releases_applied++; - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); return true; } } @@ -7273,7 +7262,7 @@ static bool svc_rel_apply_reportsem(struct nv_vgpu_device *vgpu, svc.pushes_pending++; if (!svc_sem_write(vgpu, ch->h_object, va, payload)) { svc.releases_applied++; - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); return true; } return false; @@ -7318,7 +7307,7 @@ static bool svc_rel_apply_launch(struct nv_vgpu_device *vgpu, /* handled by the exact-slot path */ } else if (!svc_sem_write(vgpu, ch->h_object, sem_va, cur)) { svc.releases_applied++; - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); return true; } } @@ -8798,6 +8787,22 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, ch->entry_want = st.sem_payload; have_cur = true; pending = 1; + /* + * fail4: apply this seed ABSOLUTE. + * The generic applier still sees the + * increment flag (inc), so leaving + * the residue in cur makes it write + * cur+payload (observed 134+1=135) + * - a completed value far past the + * guest's queued count, which + * trips the guest UVM assert + * (uvm_channel.c:204 completed <= + * queued) and kills the device. + * cur=0 makes inc-apply land the + * payload itself, exactly the + * re-seed the client polls. + */ + cur = 0; svc.pool_residue++; if (svc.pool_residue_log < 32) { svc.pool_residue_log++; @@ -9621,7 +9626,7 @@ static void svc_apply_pending(struct nv_vgpu_device *vgpu) if (!svc_sem_write(vgpu, 0, p->va, p->op ? cur + p->payload : p->payload)) { svc.releases_applied++; - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); if (gsp_sema_dbg) pr_info("sema-svc: deferred release va=0x%llx payload=%u (was cur=%u)\n", p->va, p->payload, cur); @@ -9794,7 +9799,7 @@ static u32 __maybe_unused __svc_apply_page_data_disabled(struct nv_vgpu_device * if (svc_sem_write(vgpu, 0, va, payload) == 0) { svc.releases_applied++; - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); applied++; if (payload != cur + 1) { svc.releases_jumped++; @@ -10892,7 +10897,7 @@ static void svc_notify_complete(struct nv_vgpu_device *vgpu, /* Keep the completion visible to clients that start waiting * after the event fired. */ - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); } } @@ -13109,7 +13114,7 @@ static bool svc_fake_release(struct nv_vgpu_device *vgpu, struct svc_channel *ch svc.releases_applied++; if (!gsp_sema_fake_rel) svc.releases_recovered++; - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); } } } @@ -14102,21 +14107,6 @@ static void svc_opdef_drop_stale(struct nv_vgpu_device *vgpu, if (!e->active || e->vgpu != vgpu || e->h_object != ch->h_object || e->entry_idx == keep_idx) continue; - /* - * STALLFREE r228 (entry=82 of 0x5c000059): a slot whose entry - * the ring has NOT consumed in this put epoch is NOT stale. A - * pin-batch rewind moves last_get backwards over an unconsumed - * entry and re-decodes it; clearing the slot here restarted the - * 10 s opdef deadline on every re-walk, so the hold re-armed - * forever (log: 'opdef-clear caller=4 entry=82' + 'opdef: hold - * entry=82' repeating while the 1 MiB op's operand never - * resolved, rc=-2; put=84 get=82 last=82 frozen for 10 s). The - * epoch bit is set by svc_replay_note on consume, so only an - * entry that was truly consumed has its withheld set - * delivered-late and dropped here. - */ - if (!test_bit(e->entry_idx, ch->slot_done_epoch)) - continue; if (e->n) svc_fwd_rel_apply_all(vgpu, ch, e->rel, e->n); svc_opdef_clear(e, SVC_OPDEF_CLR_STALE); @@ -14155,31 +14145,6 @@ static void svc_opdef_drop_gone(struct nv_vgpu_device *vgpu, } } -/* - * STALLFREE: drop every opdef slot bound to one channel handle whose - * first-pending stamp PREDATES `before` (the rebinding's reconcile instant). - * A context switch/teardown invalidates the handle's withheld sets - their - * waiters are gone and the releases must not ride the reused channel (the - * opdef-hold class). The `before` filter is the provable-safety rule: a slot - * the fresh binding creates after its registration (the reconcile runs at - * the top of the first pump pass, before that pass's walk) always has - * since >= before and is NEVER touched; only the dead context's slots are - * dropped. 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, - unsigned long before) -{ - 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 && - time_before(e->since, before)) - svc_opdef_drop_counted(e); - } -} - static void svc_opdef_reset_all(void) { int i; @@ -17356,130 +17321,52 @@ static void svc_userd_sweep(struct nv_vgpu_device *vgpu, struct svc_channel *ch, * SVC_GR_STALE_WEDGE_MS (the (last_get, put) pair unchanged across the * window): * - * 1. stale epoch (host caught up, last_get == put): the ring still - * carries a session's residue (put > 1). The host resets the stale - * publish state - zero the host-owned completion word and - * counter_last (m181's resync; the residual put is NEVER published, - * see the r207 far-jump note in svc_counter_publish) - and, when the - * whole consumed range delivered nothing (counter_last == 0 and - * submissions >= 8), additionally rewinds last_get to slot 0 - * (reason=stale-dead-range) so the fresh session's own entries, which - * start at slot 0, are walked. The forced-replay marker - * (wd_nocap_put) makes that re-walk decode releases only (idempotent, - * forward-only) and never re-capture/re-forward a dead launch. - * 2. stale replay: last_get pinned behind put while put == get (the + * 1. stale-epoch: a GR channel that still carries a residual put + * (put > 1 at this pass, publish withheld) and whose ring the host + * believes is fully consumed (last_get == put) - the fresh session + * never proved its switch with a put drop. The host applies the + * m181 recovery on a TIMEOUT instead: arm the counter publish and + * void the withheld publish state (no last_get rewind - a timeout is + * not proof the ring is the dead session's; the proven m181 rewind + * stays reserved for its put-drop signature). This is the recovery + * the killed-client rerun needs. + * + * 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). 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. + * 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). * - * Nothing here can fire on a green channel: a green channel either moves - * put or consumes its first entries within milliseconds (submissions > 0), - * so the no-progress window never forms; the stale-replay leg - * additionally requires entries consumed during a stalled window, which - * only the rewind re-opening of a consumed window produces. + * Nothing here can fire on a green channel: a fresh channel has put <= 1 + * (signature 1) or consumes its first entries within milliseconds + * (submissions > 0); signature 2 additionally requires BOTH a stalled + * (last_get, put) pair for 3 s with no pending producer work AND consumed + * entries during that window, which 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 - * yields nothing is NOT silently consumed: the pump requests an immediate - * rebuild/pin pass and leaves the entry pending, so the first launch of a - * fresh client executes on its FIRST attempt instead of being dropped - * before the page translations land (r229/r231: attempt 1 stalls, attempt - * 2 works because the rebuild caught up). Stale-free cost: at most this - * 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) { - bool catchup, residual, dead_reset, replay_cand, stalled_cand; - bool fire_replay, fire_reset, fire_stall; + bool residual, replay; const char *reason = ""; unsigned long waited; if (ch->engine_type || !ch->gpfifo_entries) return; - /* - * New producer work (put advanced) clears the per-put-epoch latches - * and the replay cooldown: the next stale region gets its own - * recovery. - */ - 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; - + /* New work (put advanced) clears the replay cooldown immediately. */ + if (ch->wd_rewind_off_until && ch->wd_put != put) + ch->wd_rewind_off_until = 0; if (ch->wd_since && (ch->wd_put != put || ch->wd_last_get != ch->last_get)) ch->wd_since = 0; /* progress (or a new position): re-arm */ - - catchup = (ch->last_get == put); - 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 - * latch is unset. Two additive recoveries: - * - residual: the host published its own value for this channel at - * some point (counter_last != 0), so reset the stale publish - * state (zero the word, m181 semantics). - * - dead-reset: nothing was ever published for this channel - * (counter_last == 0) and the consumed range delivered nothing - * while being non-trivial (submissions >= 8): the whole walked - * range was the dead session's ring. Rewind last_get to 0 so the - * fresh session's own entries (which start at slot 0) get walked; - * the re-walk forces replay so a dead launch is never re-captured - * or re-forwarded. - */ - residual = (catchup && put > 1 && !ch->wd_epoch_done && - !ch->gr_pub_armed && ch->counter_last != 0); - dead_reset = (catchup && put > 1 && !ch->wd_epoch_done && - !ch->gr_pub_armed && ch->counter_last == 0 && - ch->submissions >= 8); - /* - * STALLFREE r228: stalled PENDING entry. The producer has submitted - * work the host has not consumed (put > get) and the entry loop has - * made no progress - position AND submissions static across the - * window - while no bounded owner is active for the stuck entry: no - * unreadable-push grace (defer_since), no no-capture window, no - * opdef operand slot, no m150 hold window. That combination is a - * genuinely unexplained stall (r228: the opdef deadline kept being - * reset by rewind replays, fixed in svc_opdef_drop_stale; this leg - * is the safety net for any future variant that slips the bounded - * owners). A green channel always advances submissions (consume) or - * sets one of the bounded owners on a pending entry, so the leg - * cannot fire there. - */ - stalled_cand = (!catchup && put != get && !ch->defer_since && - !ch->gr_nocap_since && - !(ch->gr_hold_idx == (u32)ch->last_get && - time_before(jiffies, ch->gr_hold_until)) && - !svc_opdef_find(vgpu, ch->h_object, - (u32)ch->last_get)); - if (!residual && !dead_reset && !replay_cand && !stalled_cand) { + residual = (!ch->gr_pub_armed && put > 1 && ch->last_get == put); + replay = (ch->last_get != put && put == get && + ch->wd_since && ch->submissions != ch->wd_sub); + if (!residual && !replay) { ch->wd_since = 0; ch->wd_put = put; ch->wd_last_get = ch->last_get; @@ -17496,43 +17383,21 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu, msecs_to_jiffies(SVC_GR_STALE_WEDGE_MS))) return; waited = jiffies_to_msecs(jiffies - ch->wd_since); - fire_reset = dead_reset; - /* - * The replay leg only fires with proof of a rewind livelock: entries - * were consumed during the window while the position did not move - * (the rewind re-opened an already-consumed window). Without that - * 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 && - 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 - * the entry is genuinely parked with no bounded owner. - */ - fire_stall = stalled_cand && ch->submissions == ch->wd_sub; - if (!residual && !fire_reset && !fire_replay && !fire_stall) { - /* - * 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) { + if (residual) { /* - * Reset the stale publish state. The residual put is NEVER - * published: writing a far-forward value into the fresh - * client's completion word is the r207/mM2 far-jump wedge - * (UVM_GPU_SEMAPHORE_MAX_JUMP), which is exactly what - * gr_pub_armed exists to prevent. Only a word the host itself - * published this session is zeroed (m181 semantics) so a - * channel the host never wrote (counter_last == 0) is left - * untouched; the arm stays reserved for the proven put-drop - * (m181) and the pristine put <= 1 discovery. + * m181 recovery on timeout: the fresh session never dropped + * the residual put, so prove the epoch switch here. Arm the + * publish (the withheld completion counter was the plausible + * ctx-init wait - r225's client polled service-interrupts 1/s + * with no host edge) and void any publish state the stale + * pass advanced, exactly like m181; the guest word itself is + * only zeroed when the host authored it. No last_get rewind: + * a timeout is not proof that the ring is the dead session's + * (re-walking it could re-capture a stale launch), so the + * proven m181 rewind stays reserved for its put-drop + * signature; the client's own first put write will trigger it. */ + ch->gr_pub_armed = true; if (ch->counter_last) { u64 upa = ch->release_pa ? ch->release_pa : ch->counter_pa; @@ -17568,51 +17433,21 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu, } ch->counter_last = 0; } - } - if (fire_reset || fire_stall) { - /* - * The canonical unstuck: rewind to slot 0 so the fresh - * session's own entries (which start there) get walked, with - * forced replay (wd_nocap_put) so the re-walk decodes releases - * only and never re-captures a launch; once per put epoch. - */ - ch->wd_epoch_done = true; - ch->last_get = 0; - ch->wd_nocap_put = put; - } - if (fire_replay) { - /* - * 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. - */ + reason = "stale-epoch"; + } else { + /* Drop the rewind-reopened consumed window; cool the rewind. */ ch->last_get = put; - ch->wd_epoch_done = true; + ch->wd_rewind_off_until = jiffies + + msecs_to_jiffies(8u * SVC_GR_STALE_WEDGE_MS); + reason = "stale-replay"; } - if (residual || fire_reset || fire_replay) - ch->wd_epoch_done = true; ch->wd_since = 0; ch->wd_put = put; ch->wd_last_get = ch->last_get; svc.gr_stale_wedge++; - if (fire_replay) - reason = "stale-replay"; - else if (fire_reset) - reason = "stale-dead-range"; - else if (fire_stall) - 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 clamp=%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\n", ch->h_object, ch->gpfifo_va, (u32)ch->last_get, - put, get, ch->submissions, waited, reason, - (fire_reset || fire_stall) ? 1 : 0, - fire_replay ? 1 : 0, fire_stall ? 1 : 0, - ch->counter_pa, ch->release_pa); + put, get, ch->submissions, waited, reason); } static void svc_pump_channels(struct nv_vgpu_device *vgpu) @@ -18010,49 +17845,6 @@ 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, 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, - * its binding never reached the pump (pre-registration - * class) and this mechanism cannot apply. - */ - if (svc.gr_newbind_log < 16) { - svc.gr_newbind_log++; - pr_info("vgsp-gr: GR-STALL-newbind h=0x%x put=%u get=%u action=window reason=stale-entry-newbind\n", - ch->h_object, put, get); - } - 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 @@ -18218,19 +18010,6 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) */ entry_replay = same && ch->slot_ops_complete[idx]; - /* - * STALLFREE r227: while a stale-epoch recovery - * re-walks a dead session's consumed range - * (wd_nocap_put set by the watchdog), force - * replay for the dead slots: their releases - * are re-decoded/applied forward-only - * (idempotent) but a dead launch is never - * re-captured or re-forwarded. Cleared by the - * watchdog when the walk catches up. - */ - if (!entry_replay && ch->wd_nocap_put && - (u32)idx < ch->wd_nocap_put) - entry_replay = true; if (same) entry_done = ch->slot_ops_done[idx]; } @@ -18536,42 +18315,6 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) &entry_done); if (rehold) ch->gr_rehold_idx = ~0u; - /* - * STALLFREE r230: a fresh - * binding's entry that decoded - * NOTHING (no release, no QMD, - * no ops) is the r229 attempt-1 - * class: the page content read - * before the client's real - * writes/translations landed, so - * consuming it would drop the - * launch. Hold it for the short - * new-binding window and ask for - * an immediate rebuild; after the - * window it consumes as before, so - * the cost is bounded. - */ - if (!ch->engine_type && - !entry_replay && - svc_rel_count == rel_n_iter && - svc_gr_qmd_seen == 0 && - put == get && - ch->wd_newbind_hold_until && - time_before(jiffies, - ch->wd_newbind_hold_until)) { - if (!ch->defer_since) - ch->defer_since = - jiffies; - svc.rebuild_now = true; - if (svc.gr_pending_map < 16) { - svc.gr_pending_map++; - pr_warn("vgsp-gr: GR-STALL-pending-map h=0x%x va=0x%llx entry=%u action=rebuild reason=stale-entry-newbind\n", - ch->h_object, va, - (u32)idx); - } - kfree(pb); - break; - } /* * Record what ran for this entry * identity before any hold path can @@ -19634,31 +19377,6 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) !ch->defer_since) ch->defer_since = jiffies; - /* - * STALLFREE r230: a fresh - * binding's unmapped entry is - * the host-readiness race - - * request the immediate rebuild - * so the pages resolve inside - * this grace instead of the - * 10 s cadence (r229/r231: - * attempt 1 lost exactly - * here, attempt 2 won after - * the rebuild caught up). - */ - if (!ch->engine_type && - put == get && - ch->wd_newbind_hold_until && - time_before(jiffies, - ch->wd_newbind_hold_until)) { - svc.rebuild_now = true; - if (svc.gr_pending_map < 16) { - svc.gr_pending_map++; - pr_warn("vgsp-gr: GR-STALL-pending-map h=0x%x va=0x%llx entry=%u action=rebuild reason=stale-entry-newbind\n", - ch->h_object, va, - (u32)idx); - } - } svc.gpfifo_nomap++; kfree(pb); break; @@ -20368,6 +20086,20 @@ 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 @@ -20772,27 +20504,7 @@ static int svc_thread(void *arg) * svc_rebuild() publishes (svc.last_build). */ sess = svc_guest_get(vgpu, true); - /* - * STALLFREE r230: a pending rebuild request from the - * pump (a fresh binding's entry hit an unmapped page) - * forces the rebuild now instead of waiting for the - * 10 s cadence, so the first attempt's pages resolve. - */ - if (svc.rebuild_now) { - svc.rebuild_now = false; - /* - * Bounded proof (r234 asks): a pump-requested - * rebuild was actually consumed by the service - * thread here (the only consumer). - */ - if (svc.gr_rebuild_log < 16) { - svc.gr_rebuild_log++; - pr_info("vgsp-gr: GR-STALL-rebuild consumed=1 by=svc_thread action=rebuild reason=stale-entry-newbind\n"); - } - svc_rebuild(vgpu); - if (sess) - sess->last_build = svc.last_build; - } else if (svc_sess_flush || !svc.direct_base || + if (svc_sess_flush || !svc.direct_base || !sess || time_after(jiffies, (unsigned long)(sess->last_build + @@ -21320,6 +21032,6 @@ int gsp_sema_service_sem_write(struct nv_vgpu_device *vgpu, u32 h, u64 va, * after the write still receives the completion event. */ if (!rc) - svc.post_hint_until = jiffies + 10 * HZ; + svc.post_hint_until = jiffies + msecs_to_jiffies(SVC_POST_HINT_MS); return rc; } -- cgit v1.2.3