summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c123
-rw-r--r--kernel/gsp_phys_booter.h2
-rw-r--r--kernel/gsp_sema_service.c29
3 files changed, 125 insertions, 29 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index cc33e31..af62e5c 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -18856,6 +18856,7 @@ struct gsp_phys_gr_mme_release_state {
bool valid;
bool armed;
bool fired;
+ bool consumed; /* release no longer owed (released/ctx/err) */
u32 h_object;
u32 gen;
u32 held;
@@ -18864,6 +18865,11 @@ struct gsp_phys_gr_mme_release_state {
unsigned long due_j;
u32 boot_n;
u32 fired_gen; /* pack_done_gen already released (no retries) */
+ /* The launch that armed this record (h + push); a later launch of the
+ * same identity is "the arming launch", never a client that consumed
+ * the release. */
+ u32 arm_h;
+ u64 arm_push;
/* capture snapshot (see struct gsp_phys_gr_submit) */
u32 qmd[GSP_PHYS_GR_QMD_WORDS];
u32 n_pages;
@@ -18945,6 +18951,9 @@ static void gsp_phys_gr_mme_release_save(const struct gsp_phys_gr_submit *req,
s->valid = false;
s->armed = false;
s->fired = false;
+ s->consumed = false;
+ s->arm_h = 0;
+ s->arm_push = 0;
s->h_object = req->h_object;
s->gen = gen;
s->held = held;
@@ -18989,15 +18998,17 @@ static void gsp_phys_gr_mme_release_save(const struct gsp_phys_gr_submit *req,
/*
* Arm once the packed program is complete/resident. The record survives
* partial emissions, so the completing launch (which may carry no held CALL
- * runs of its own) arms the last held-call window. A previously armed release
- * is superseded by a newer record; a fired one is never re-armed (one fire
- * per boot, no retries).
+ * runs of its own) arms the last held-call window. Idempotent: an already
+ * armed release keeps its deadline (the pump calls this every pass as a
+ * re-arm safety net). `h`/`push` identify the arming launch, so a later
+ * launch of that same identity is never mistaken for a client that consumed
+ * the release. A fired or consumed release is never re-armed (no retries).
*/
-static void gsp_phys_gr_mme_release_arm(u32 gen)
+static void gsp_phys_gr_mme_release_arm(u32 h, u64 push, u32 gen)
{
struct gsp_phys_gr_mme_release_state *s = &gsp_phys_gr_mme_release;
unsigned long flags;
- bool pack_done, golden, superseded = false, ok = false, fresh;
+ bool pack_done, golden, ok = false, fresh;
u32 ms, h_object, held, win_n, pdg;
if (!READ_ONCE(gsp_phys_rmcall_gr_mme_pack_release))
@@ -19007,14 +19018,10 @@ static void gsp_phys_gr_mme_release_arm(u32 gen)
h_object = s->h_object;
held = s->held;
win_n = s->win_n;
- if (s->fired) {
+ if (s->fired || s->consumed || s->armed) {
spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
return;
}
- if (s->armed) {
- s->armed = false;
- superseded = true;
- }
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);
@@ -19030,18 +19037,67 @@ static void gsp_phys_gr_mme_release_arm(u32 gen)
fresh && golden) {
s->armed = true;
s->gen = gen;
+ s->arm_h = h;
+ s->arm_push = push;
s->due_j = jiffies + msecs_to_jiffies(ms);
ok = true;
}
spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
- if (superseded)
- pr_info("vgsp-gr: MME-CARRY-CANCEL reason=superseded mode=release h=0x%x held=%u win=%u\n",
- h_object, held, win_n);
if (ok)
pr_info("vgsp-gr: MME-CARRY-ARM mode=release h=0x%x held=%u win=%u due_ms=%u\n",
h_object, held, win_n, ms);
}
+/*
+ * Pump-side re-arm safety net: the builder arms at the pack completion and at
+ * the held-call snapshot, but a launch that races the grace can leave the
+ * record valid and disarmed. Re-arm it here (idempotent) so the release still
+ * fires at the deadline. Terminal cancels set consumed, so a released or
+ * context-voided record is never revived.
+ */
+void gsp_phys_gr_mme_release_rearm(void)
+{
+ struct gsp_phys_gr_mme_release_state *s = &gsp_phys_gr_mme_release;
+ 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))
+ return;
+ gsp_phys_gr_mme_release_arm(arm_h ? arm_h : READ_ONCE(s->h_object),
+ arm_push ? arm_push :
+ READ_ONCE(s->push_va),
+ READ_ONCE(s->gen));
+}
+
+/* True when (h, push) is the launch that armed the pending release. */
+bool gsp_phys_gr_mme_release_is_arming(u32 h, u64 push)
+{
+ 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->arm_push == push;
+ spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
+ 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;
@@ -19069,7 +19125,8 @@ bool gsp_phys_gr_mme_release_take(u32 h_object, u32 *held, u32 *win)
u32 sh, sheld, swin, pdg;
spin_lock_irqsave(&gsp_phys_gr_mme_release_lock, flags);
- if (!s->armed || !time_after_eq(jiffies, s->due_j)) {
+ if (!s->armed || s->consumed ||
+ !time_after_eq(jiffies, s->due_j)) {
spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
return false;
}
@@ -19094,6 +19151,8 @@ bool gsp_phys_gr_mme_release_take(u32 h_object, u32 *held, u32 *win)
if (reason) {
s->armed = false;
s->fired = false;
+ s->consumed = true;
+ s->valid = false;
spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
pr_info("vgsp-gr: MME-CARRY-CANCEL reason=%s mode=release h=0x%x held=%u win=%u\n",
reason, sh, sheld, swin);
@@ -19135,6 +19194,7 @@ void gsp_phys_gr_mme_release_complete(void)
s->armed = false;
s->fired = false;
s->valid = false;
+ s->consumed = true;
spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
if (fired)
pr_info("vgsp-gr: MME-CARRY-COMPLETE mode=release\n");
@@ -19154,6 +19214,8 @@ void gsp_phys_gr_mme_release_cancel(const char *reason)
swin = s->win_n;
s->armed = false;
s->fired = false;
+ s->consumed = true;
+ s->valid = false;
spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
if (had)
pr_info("vgsp-gr: MME-CARRY-CANCEL reason=%s mode=release h=0x%x held=%u win=%u\n",
@@ -19174,6 +19236,8 @@ void gsp_phys_gr_mme_release_failed(int rc)
swin = s->win_n;
s->armed = false;
s->fired = false;
+ s->consumed = true;
+ s->valid = false;
spin_unlock_irqrestore(&gsp_phys_gr_mme_release_lock, flags);
if (!had)
return;
@@ -21693,6 +21757,13 @@ 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
@@ -22103,14 +22174,18 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
stream_damaged = gsp_phys_gr_stream_damaged(req->push_va,
req->stream_rel);
/*
- * A real client 3D window is the "next launch" the saved-window
- * release carrier was waiting for: cancel a pending release so
- * the client's own window (which may run or hold the calls)
- * wins. The hold point below can re-arm from this launch's own
- * snapshot when the pack is complete.
+ * The launch that armed the saved-window release is not a
+ * "next client launch" that consumed it: it is the same build
+ * (and a duplicate/retry of it) that left the held CALL runs
+ * unrun. Never cancel on it - just name the hold. Other client
+ * windows also leave the release armed; the only "calls
+ * actually released" cancel is the MME-PACK-REARM edge below.
*/
- if (!carrier && !release && req->stream_n)
- gsp_phys_gr_mme_release_cancel("client-first");
+ if (!carrier && !release && req->stream_n &&
+ gsp_phys_gr_mme_release_is_arming(req->h_object,
+ req->push_va))
+ pr_info_ratelimited("vgsp-gr: MME-CARRY-HOLD reason=arming-launch h=0x%x push=0x%llx\n",
+ req->h_object, req->push_va);
/*
* SESSION 153-CONTINUED-63: MME START-ADDRESS RAM completion.
* The prelude capture is capped at 512 words, so the client's
@@ -23557,6 +23632,8 @@ if (gsp_phys_gr_slot_kept(j, sa_mask,
* launch may carry none).
*/
gsp_phys_gr_mme_release_arm(
+ req->h_object,
+ req->push_va,
pl_gen);
pr_info("vgsp-gr: MME-PRELUDE pack ir_words=%u runs=%u sa=%u h=0x%x push=0x%llx\n",
maxa, nruns,
@@ -24476,7 +24553,9 @@ if (gsp_phys_gr_slot_kept(j, sa_mask,
if (held) {
gsp_phys_gr_mme_release_save(req, held, win3d_n,
pl_gen);
- gsp_phys_gr_mme_release_arm(pl_gen);
+ gsp_phys_gr_mme_release_arm(req->h_object,
+ req->push_va,
+ pl_gen);
}
if (pelided)
pr_info_ratelimited("vgsp-gr: PAIR-CHAIN held-elide %u word(s) of program-pair runs dropped (pairs installed gen=%u h=0x%x; 0x2058 other-writer) push=0x%llx\n",
diff --git a/kernel/gsp_phys_booter.h b/kernel/gsp_phys_booter.h
index a27225b..21eb1fc 100644
--- a/kernel/gsp_phys_booter.h
+++ b/kernel/gsp_phys_booter.h
@@ -597,6 +597,8 @@ void gsp_phys_gr_mme_carry_failed(int rc);
*/
bool gsp_phys_gr_mme_release_peek(u32 *h_object);
bool gsp_phys_gr_mme_release_take(u32 h_object, u32 *held, u32 *win);
+void gsp_phys_gr_mme_release_rearm(void);
+bool gsp_phys_gr_mme_release_is_arming(u32 h, u64 push);
void gsp_phys_gr_mme_release_cancel(const char *reason);
void gsp_phys_gr_mme_release_failed(int rc);
void gsp_phys_gr_mme_release_complete(void);
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 6d72a62..26d3b1a 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -50031,15 +50031,19 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
/*
* Saved-window release carrier (sema_gl_mme_pack_release). After the
- * channel loop (a client window decoded in this pass wins and cancels
- * the pending release), fire the saved held-call window once the pack
- * completed and the settle grace expired. Same gates as the
- * continuation carrier, except the FE-busy defer (this launch carries
- * a real window, not a LOAD-ONLY carrier).
+ * channel loop (so a client window decoded in this pass is offered
+ * first), re-arm the saved held-call window if a race left the record
+ * valid but disarmed, then fire it once the pack completed and the
+ * settle grace expired. Same gates as the continuation carrier, except
+ * the FE-busy defer (this launch carries a real window, not a
+ * LOAD-ONLY carrier). A real client window never cancels the release:
+ * only the MME-PACK-REARM edge (calls actually released) does.
*/
{
u32 rel_h = 0;
+ bool found = false;
+ gsp_phys_gr_mme_release_rearm();
if (gsp_phys_gr_mme_release_peek(&rel_h)) {
int ci;
@@ -50048,14 +50052,25 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
if (c->h_object != rel_h || c->engine_type)
continue;
- if (svc_gr_cand_unoffered_for(rel_h))
+ found = true;
+ if (svc_gr_cand_unoffered_for(rel_h)) {
+ pr_info_ratelimited("vgsp-gr: MME-CARRY-HOLD reason=client-candidate h=0x%x\n",
+ rel_h);
break;
+ }
if (svc_fwd_hold.active ||
- test_bit(SVC_FWD_INFLIGHT, &svc_fwd_state))
+ test_bit(SVC_FWD_INFLIGHT,
+ &svc_fwd_state)) {
+ pr_info_ratelimited("vgsp-gr: MME-CARRY-HOLD reason=request-inflight h=0x%x\n",
+ rel_h);
break;
+ }
(void)svc_gr_carrier_request(vgpu, c, true);
break;
}
+ if (!found)
+ pr_info_ratelimited("vgsp-gr: MME-CARRY-HOLD reason=no-channel h=0x%x\n",
+ rel_h);
}
}