summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-15 15:23:27 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-15 15:23:27 -0500
commit70b49517fe95940c7e91c3d7fdb0ea3014a1534f (patch)
tree83607b8209aab0e1b751772dcfcd29e6abe08500
parentc9661edb46f087c67ffd9dca7ac30b291503ecd3 (diff)
downloadopen-iov-70b49517fe95940c7e91c3d7fdb0ea3014a1534f.tar.gz
open-iov-70b49517fe95940c7e91c3d7fdb0ea3014a1534f.zip
vgsp: eng59c - preserve the saved release window across the beef channel recycle; defer non-ready takes
c765/c766: the release carrier saved the held 324/728 B window, then the client re-registered the beef channel before the pack completed. The follow-up's chan_ctx_reset cancelled the saved record unconditionally (consumed=true, valid=false) even though keep_done_across_recycle=1 means the engine context and packed program survive; the pack-completion arm then early-returned and the release never fired. With keep_done_across_recycle=1 the re-register is a client-handle recycle, not a context loss: keep the release record. Cancel it only in the genuine !keep_done wipe path. Also make release_take defer (not consume) on not-armed/grace/pack-not-resident with bounded MME-CARRY-HOLD receipts; only terminal conditions or a failed fire consume. release_rearm now runs unconditionally with the knob on and release_arm gates on pack_done, so the record survives the save->completion gap. Build rc 0; validation pending.
-rw-r--r--kernel/gsp_phys_booter.c82
1 files changed, 53 insertions, 29 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index af62e5c..0180da1 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -19025,6 +19025,19 @@ static void gsp_phys_gr_mme_release_arm(u32 h, u64 push, u32 gen)
pdg = READ_ONCE(gsp_phys_gr_mme_pack_done_gen);
pack_done = (READ_ONCE(gsp_phys_gr_mme_pack_done_h) == h_object ||
pdg != 0u);
+ if (!pack_done) {
+ /*
+ * The held-call record is saved but the pack is still partial
+ * (or the completion has not landed yet): defer, never
+ * consume. The pump calls this every pass, so the record is
+ * re-armed the moment pack_done_gen turns non-zero.
+ */
+ spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
+ if (s->valid && held && win_n)
+ pr_info_ratelimited("vgsp-gr: MME-CARRY-HOLD reason=pack-not-resident mode=release h=0x%x held=%u win=%u\n",
+ h_object, held, win_n);
+ return;
+ }
golden = gsp_phys_gr_golden_ready();
/*
* One fire per pack completion: a completion generation already
@@ -19061,9 +19074,14 @@ void gsp_phys_gr_mme_release_rearm(void)
u32 arm_h = READ_ONCE(s->arm_h);
u64 arm_push = READ_ONCE(s->arm_push);
- if (!READ_ONCE(gsp_phys_rmcall_gr_mme_pack_release) ||
- !READ_ONCE(gsp_phys_gr_mme_pack_done_gen))
+ if (!READ_ONCE(gsp_phys_rmcall_gr_mme_pack_release))
return;
+ /*
+ * Unconditional on a valid, non-consumed record: release_arm() is the
+ * gate (it no-ops until pack_done_gen != 0 and the record is still
+ * owed). This keeps the saved record alive across the 9 s gap between
+ * the held-call save and the pack completion.
+ */
gsp_phys_gr_mme_release_arm(arm_h ? arm_h : READ_ONCE(s->h_object),
arm_push ? arm_push :
READ_ONCE(s->push_va),
@@ -19084,20 +19102,6 @@ bool gsp_phys_gr_mme_release_is_arming(u32 h, u64 push)
return ret;
}
-/* True when the pending release belongs to channel h (re-register cancel). */
-static bool gsp_phys_gr_mme_release_on_channel(u32 h)
-{
- struct gsp_phys_gr_mme_release_state *s = &gsp_phys_gr_mme_release;
- unsigned long flags;
- bool ret;
-
- spin_lock_irqsave(&gsp_phys_gr_mme_release_lock, flags);
- ret = (s->armed || s->fired) &&
- (s->arm_h == h || s->h_object == h);
- spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
- return ret;
-}
-
bool gsp_phys_gr_mme_release_peek(u32 *h_object)
{
struct gsp_phys_gr_mme_release_state *s = &gsp_phys_gr_mme_release;
@@ -19121,15 +19125,28 @@ bool gsp_phys_gr_mme_release_take(u32 h_object, u32 *held, u32 *win)
struct gsp_phys_gr_mme_release_state *s = &gsp_phys_gr_mme_release;
const char *reason = NULL;
unsigned long flags;
- bool pack_done;
+ bool pack_done, retryable = false;
u32 sh, sheld, swin, pdg;
spin_lock_irqsave(&gsp_phys_gr_mme_release_lock, flags);
- if (!s->armed || s->consumed ||
- !time_after_eq(jiffies, s->due_j)) {
+ if (s->consumed) {
spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
return false;
}
+ if (!s->armed || !time_after_eq(jiffies, s->due_j)) {
+ const char *defer = s->armed ? "grace" : "not-armed";
+
+ sh = s->h_object;
+ spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
+ /*
+ * Deferral, not a verdict: the record stays valid and armed
+ * (or is re-armed by the pump) until the grace/arm condition
+ * is met.
+ */
+ pr_info_ratelimited("vgsp-gr: MME-CARRY-HOLD reason=%s mode=release h=0x%x\n",
+ defer, sh);
+ return false;
+ }
sh = s->h_object;
sheld = s->held;
swin = s->win_n;
@@ -19144,11 +19161,25 @@ bool gsp_phys_gr_mme_release_take(u32 h_object, u32 *held, u32 *win)
reason = "not-beef";
else if (!gsp_phys_gr_golden_ready())
reason = "golden-lost";
- else if (!pack_done)
- reason = "pack-lost";
else if (pdg != 0u && pdg == s->fired_gen)
reason = "budget";
+ else if (!pack_done) {
+ /*
+ * pack-not-resident is retryable: the pack completion (which
+ * may still be in flight) will arm/fire later. Never consume
+ * the saved record on it.
+ */
+ reason = "pack-lost";
+ retryable = true;
+ }
if (reason) {
+ if (retryable) {
+ spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock,
+ flags);
+ pr_info_ratelimited("vgsp-gr: MME-CARRY-HOLD reason=pack-not-resident mode=release h=0x%x\n",
+ sh);
+ return false;
+ }
s->armed = false;
s->fired = false;
s->consumed = true;
@@ -21757,13 +21788,6 @@ void gsp_phys_gr_mme_chan_ctx_reset(u32 h)
READ_ONCE(gsp_phys_rmcall_gr_mme_golden_force)))
return;
/*
- * A re-register of the saved-window release's own channel is a fresh
- * context for the window it would replay: void the pending release
- * even when another channel owns the packed load.
- */
- if (gsp_phys_gr_mme_release_on_channel(h))
- gsp_phys_gr_mme_release_cancel("chan-ctx-reset");
- /*
* Only the channel that owns the in-flight or completed packed load
* loses its context on (re-)registration; an unrelated channel's
* recycle (the client re-registers its whole family per fire) must
@@ -21773,7 +21797,6 @@ void gsp_phys_gr_mme_chan_ctx_reset(u32 h)
h != READ_ONCE(gsp_phys_gr_mme_pack_done_h))
return;
gsp_phys_gr_mme_carry_cancel("chan-ctx-reset");
- gsp_phys_gr_mme_release_cancel("chan-ctx-reset");
/*
* eng43: sema_gl_mme_keep_done_across_recycle=1 - the re-register
* recycles the client handle but leaves the GR engine context (and
@@ -21788,6 +21811,7 @@ void gsp_phys_gr_mme_chan_ctx_reset(u32 h)
* Default 0 = legacy (identical to the pre-knob behaviour).
*/
if (!READ_ONCE(gsp_phys_rmcall_gr_mme_keep_done_across_recycle)) {
+ gsp_phys_gr_mme_release_cancel("chan-ctx-reset");
WRITE_ONCE(gsp_phys_gr_mme_pack_off, 0);
WRITE_ONCE(gsp_phys_gr_mme_pack_sa, false);
WRITE_ONCE(gsp_phys_gr_mme_pack_load_h, 0);