summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-31 22:16:00 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-31 22:16:00 -0400
commit12442327cda834a7fcb13a6e010e1a747cb9110c (patch)
tree5dbb71f333106115d3aa36555d1caf88a8c8d6c5
parentdcd9ce6b194cfb3a74c2aa39c7fd650fee1e6b99 (diff)
downloadopen-iov-12442327cda834a7fcb13a6e010e1a747cb9110c.tar.gz
open-iov-12442327cda834a7fcb13a6e010e1a747cb9110c.zip
vgsp: sema_gl_mme_block_cap=2048 (blocks >~2050 words never start on engine - CONT-78 wall root cause), run-aligned prelude drain with generation-keyed cursor (3089-word program over 2 launches, latch on final part, WEDGE-RECOVER rewinds), attr prelude same cap, sema_gl_mme_nop_param_mask (parameter-conserving NOP: call-run header rewritten to CALL_MME_DATA port) - r1177: full program ships (words=3089 covered=55) + blocks 1327-2048 all retire; bisect: slot 57 PARKS (keep=5|1<<57 -> 0 retires/6 fails, grfifo frozen events=0, no poison; r1142 CALL_MME_MACRO(57) class); NOP transform fires (26 runs retargeted) but unvalidated on wedged boots; next: healthy boot validation sequence (a)keep=5 (b)+1<<57 parks (c)+nop_param=1<<57 (d)sa_stub_all=0 -> N/N stores - SESSION 153 r1173-r1179
-rw-r--r--kernel/gsp_phys_booter.c252
1 files changed, 199 insertions, 53 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 7d861ed..da3ea83 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -17577,6 +17577,54 @@ MODULE_PARM_DESC(sema_gl_mme_keep_mask,
"Slots whose CALL_MME_MACRO/DATA runs are never dropped/stubbed (u64 bitmask; one slot at a time for macro re-enable)");
/*
+ * SESSION 153-CONTINUED-79: per-launch method-block word cap + prelude drain.
+ * The r1172-r1175 A/B: every beef launch whose emitted block exceeded ~2000
+ * words (3083-word full-SA prelude + window, 3315-3484 words) NEVER STARTED
+ * on the physical engine (MME-FAST events=0, grfifo frozen, ch_rel never
+ * written) while every block <= ~1300 words (1002-word partial capture +
+ * window) executed (retires in 90-170 us when the executed macro stayed
+ * inside the loaded IR). The failure class is fetch-side (a stuck GPFIFO
+ * entry), not content: once parked, every later entry also failed until a
+ * poison-latch TSG re-arm reset the PBDMA. The full-SA capture (55 slots,
+ * 3083 words, macros that chain past the first 15 slots e.g. macro 0 ->
+ * IR 0x201 = slot-25 entry) therefore cannot be replayed in ONE block.
+ * Emit at most gsp_phys_rmcall_gr_block_cap words per launch and drain the
+ * (SDM-sanitized, run-aligned) prelude across consecutive launches with a
+ * generation-keyed cursor; the emission latch is set only when the final
+ * part has been emitted, so a completed program is re-requested after the
+ * WEDGE-RECOVER latch clear. Default 2048; 0 = legacy 4096 module buffer.
+ */
+static u32 gsp_phys_rmcall_gr_block_cap = 2048u;
+module_param_named(sema_gl_mme_block_cap, gsp_phys_rmcall_gr_block_cap, uint,
+ 0644);
+MODULE_PARM_DESC(sema_gl_mme_block_cap,
+ "Max words emitted per GR launch method block (0 = 4096 module buffer; the >2048-word blocks never start on the physical engine)");
+
+/* Generation-keyed drain cursor for the split MME prelude emission. */
+static u32 gsp_phys_gr_mme_pre_emit_gen;
+static u32 gsp_phys_gr_mme_pre_emit_h;
+static u32 gsp_phys_gr_mme_pre_emit_off;
+
+/*
+ * SESSION 153-CONTINUED-79: parameter-conserving NOP for kept parking slots.
+ * The r1177 bisect: keep={0,2,57} (full 3089-word program resident, split
+ * emission) parks the PBDMA on the emitted block (MME-FAST events=0, grfifo
+ * frozen, warm sem WEDGED) while keep={0,2} retires every launch - slot 57's
+ * CALL_MME_MACRO(57) run is the r1142 park class. Rather than drop the run
+ * (which also removes its parameter words from the stream), rewrite the call
+ * run's header to target the CALL_MME_DATA port (method+4) so the parameter
+ * words are still written (conserved) but no macro executes: the trigger
+ * word becomes a plain port write and the PBDMA never opens a macro context
+ * whose parameter drain can back up. A slot named in this mask must also be
+ * in sema_gl_mme_keep_mask (kept = retained in the window). Default 0.
+ */
+static u64 gsp_phys_rmcall_gr_nop_param_mask;
+module_param_named(sema_gl_mme_nop_param_mask, gsp_phys_rmcall_gr_nop_param_mask,
+ ullong, 0644);
+MODULE_PARM_DESC(sema_gl_mme_nop_param_mask,
+ "Kept slots whose CALL_MME_MACRO trigger is rewritten to a plain CALL_MME_DATA port write (params conserved, macro not executed; u64 bitmask)");
+
+/*
* The same stubbed-slot predicate the launch builder applies (see the
* sa_stub emit decision): a slot is stubbed when stubbing is on and either
* the all-slots knob is set, the capture holds no SA entry, or the IR
@@ -17607,7 +17655,7 @@ static bool gsp_phys_gr_slot_stubbed(u32 j, u64 sa_mask, const u32 *sa_ent)
static u32 gsp_phys_gr_mme_drop_calls(u32 *win, u32 n, u64 sa_mask,
const u32 *sa_ent, u64 *dropped_mask)
{
- u32 r = 0, w = 0, dropped = 0;
+ u32 r = 0, w = 0, dropped = 0, transform = 0;
u64 dmask = 0;
while (r < n) {
@@ -17633,8 +17681,26 @@ static u32 gsp_phys_gr_mme_drop_calls(u32 *win, u32 n, u64 sa_mask,
if (m >= 0x3800u && m <= 0x39fcu) {
u32 j = (m - 0x3800u) / 8u;
- if (gsp_phys_gr_slot_stubbed(j, sa_mask,
- sa_ent)) {
+ if ((READ_ONCE(gsp_phys_rmcall_gr_keep_mask) &
+ (1ull << j)) &&
+ (READ_ONCE(gsp_phys_rmcall_gr_nop_param_mask) &
+ (1ull << j))) {
+ /*
+ * SESSION 153-CONTINUED-79: kept +
+ * nop-param slot - keep the run but
+ * retarget its header to the DATA
+ * port so the params still land
+ * (see the sema_gl_mme_nop_param_mask
+ * comment).
+ */
+ u32 nm = 0x3804u + 8u * j;
+
+ win[r] = (h & ~0xfffu) |
+ ((nm >> 2) & 0xfffu);
+ dmask |= 1ull << j;
+ transform++;
+ } else if (gsp_phys_gr_slot_stubbed(j, sa_mask,
+ sa_ent)) {
iscall = true;
dmask |= 1ull << j;
break;
@@ -17651,6 +17717,9 @@ static u32 gsp_phys_gr_mme_drop_calls(u32 *win, u32 n, u64 sa_mask,
w += span;
r += span;
}
+ if (transform)
+ pr_info("vgsp-gr: MME-CALL-NOP %u call run(s) retargeted to the CALL_MME_DATA port (params conserved)\n",
+ transform);
if (dropped_mask)
*dropped_mask = dmask;
return dropped;
@@ -17826,8 +17895,14 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
* emission then happens on the next launch that fits.
*/
bool emit_prelude = false;
+ bool pre_done = false;
const u32 *pl = NULL;
- u32 pl_n = 0, pl_gen = 0;
+ u32 pl_n = 0, pl_gen = 0, pl_room = 0;
+ u32 block_cap = READ_ONCE(gsp_phys_rmcall_gr_block_cap);
+
+ if (block_cap < 64u ||
+ block_cap > GSP_PHYS_RMCALL_GR_METHOD_WORDS)
+ block_cap = GSP_PHYS_RMCALL_GR_METHOD_WORDS;
/*
* SESSION 153-CONTINUED-63: MME START-ADDRESS RAM completion.
* The prelude capture is capped at 512 words, so the client's
@@ -18025,18 +18100,64 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
* priv-errored (ILLEGAL_OPCODE -> poison). Force
* re-emission on every launch while any slot is kept
* (idempotent per the emission contract).
+ *
+ * SESSION 153-CONTINUED-79: the emission is drained in
+ * per-launch parts capped at block_cap words (see the
+ * sema_gl_mme_block_cap comment; oversized blocks never
+ * start). The latch (gsp_phys_gr_mme_prelude_gen/h) is
+ * set only when the final part has gone out.
*/
- if (pl && pl_n && pl_gen &&
- (READ_ONCE(gsp_phys_rmcall_gr_keep_mask) ||
- pl_gen != READ_ONCE(gsp_phys_gr_mme_prelude_gen) ||
- req->h_object != READ_ONCE(gsp_phys_gr_mme_prelude_h))) {
- if (win3d_n + 2u + 8u + pl_n + sa_block <=
- GSP_PHYS_RMCALL_GR_METHOD_WORDS) {
- emit_prelude = true;
+ if (pl && pl_n && pl_gen) {
+ /*
+ * Fixed overhead: SET_OBJECT bind (2), SA-stub
+ * block, window, and the 4x2-word release tail.
+ */
+ u32 fixed = 2u + sa_block + win3d_n + 8u;
+
+ pl_room = (fixed + 24u <= block_cap) ?
+ block_cap - fixed : 0u;
+ if (pl_room > pl_n)
+ pl_room = pl_n;
+ /*
+ * (Re)start the drain on a new generation/
+ * channel, or when the request is forced (kept
+ * slots; a context-wiping wedge recovery clears
+ * the latch) and nothing is left to drain.
+ */
+ if (pl_gen !=
+ READ_ONCE(gsp_phys_gr_mme_pre_emit_gen) ||
+ req->h_object !=
+ READ_ONCE(gsp_phys_gr_mme_pre_emit_h) ||
+ (READ_ONCE(gsp_phys_gr_mme_pre_emit_off) >=
+ pl_n &&
+ (READ_ONCE(gsp_phys_rmcall_gr_keep_mask) ||
+ pl_gen != READ_ONCE(
+ gsp_phys_gr_mme_prelude_gen)))) {
+ WRITE_ONCE(gsp_phys_gr_mme_pre_emit_gen,
+ pl_gen);
+ WRITE_ONCE(gsp_phys_gr_mme_pre_emit_h,
+ req->h_object);
+ WRITE_ONCE(gsp_phys_gr_mme_pre_emit_off, 0);
+ }
+ if (pl_room >= 24u) {
+ emit_prelude =
+ (pl_gen != READ_ONCE(
+ gsp_phys_gr_mme_prelude_gen) ||
+ req->h_object != READ_ONCE(
+ gsp_phys_gr_mme_prelude_h) ||
+ READ_ONCE(
+ gsp_phys_gr_mme_pre_emit_off) <
+ pl_n);
} else {
- pr_info("vgsp-gr: MME-PRELUDE deferred (window=%u prelude=%u sa=%u exceeds block; replaying window alone) h=0x%x\n",
- win3d_n, pl_n, sa_block,
- req->h_object);
+ static u32 pre_defer_log;
+
+ if (pre_defer_log < 8) {
+ pre_defer_log++;
+ pr_info("vgsp-gr: MME-PRELUDE deferred (window=%u prelude=%u sa=%u cap=%u) h=0x%x\n",
+ win3d_n, pl_n, sa_block,
+ block_cap,
+ req->h_object);
+ }
}
}
}
@@ -18046,52 +18167,55 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
(GSP_PHYS_RMCALL_GR_SET_OBJECT >> 2);
*p++ = GSP_PHYS_RMCALL_CLASS_GR_3D;
if (emit_prelude) {
- u32 g0 = pl_gen, g1 = 0, sdrop = 0, pwords = pl_n;
+ u32 g0 = pl_gen, g1 = 0, sdrop = 0, pwords = 0;
+ u32 doff = READ_ONCE(gsp_phys_gr_mme_pre_emit_off);
+ u32 room = (block_cap > (u32)(p - pb) + win3d_n + 8u +
+ sa_block) ?
+ block_cap - (u32)(p - pb) - win3d_n - 8u -
+ sa_block : 0u;
- if (READ_ONCE(gsp_phys_rmcall_gr_sdm_drop)) {
- u32 r = 0, w = 0;
+ /*
+ * SESSION 153-CONTINUED-79: run-aligned drain at the
+ * generation cursor; whole runs only, SDM-family
+ * single-word entries skipped exactly like the legacy
+ * sanitize (see gsp_phys_rmcall_gr_sdm_drop).
+ */
+ while (doff < pl_n && pwords + 1u <= room) {
+ u32 h = pl[doff];
+ u32 op = (h >> 29) & 7u;
+ u32 cnt = (h >> 16) & 0xfffu;
+ u32 span = ((op == 1u || op == 3u ||
+ op == 5u) && cnt &&
+ doff + 1u + cnt <= pl_n) ?
+ 1u + cnt : 1u;
- /*
- * SESSION 153-CONTINUED-59: SDM sanitize (see the
- * gsp_phys_rmcall_gr_sdm_drop comment). Walk the
- * prelude verbatim but drop single-word SDM-family
- * encodings; they are the r1102 PBENTRY offenders.
- */
- while (r < pl_n) {
- u32 h = pl[r];
- u32 op = (h >> 29) & 7u;
- u32 cnt = (h >> 16) & 0xfffu;
- u32 span = ((op == 1u || op == 3u ||
- op == 5u) && cnt &&
- r + 1u + cnt <= pl_n) ?
- 1u + cnt : 1u;
-
- if (h && (op == 0u || op == 2u ||
- op == 6u)) {
- sdrop++;
- r += span;
- continue;
- }
- memcpy(&p[w], &pl[r], (size_t)span * 4u);
- w += span;
- r += span;
+ if (doff + span > pl_n)
+ span = pl_n - doff;
+ if (READ_ONCE(gsp_phys_rmcall_gr_sdm_drop) &&
+ h && (op == 0u || op == 2u || op == 6u)) {
+ sdrop += span;
+ doff += span;
+ continue;
}
- p += w;
- pwords = w;
- } else {
- memcpy(p, pl, (size_t)pl_n * 4);
- p += pl_n;
+ if (pwords + span > room)
+ break;
+ memcpy(p, &pl[doff], (size_t)span * 4u);
+ p += span;
+ pwords += span;
+ doff += span;
}
+ WRITE_ONCE(gsp_phys_gr_mme_pre_emit_off, doff);
+ pre_done = (doff >= pl_n);
/* seqcheck: a mid-copy append must not be recorded as
* emitted (the copy may be a torn prefix). */
gsp_sema_mme_prelude_get(NULL, &g1);
- if (g1 == g0) {
+ if (pre_done && g1 == g0) {
WRITE_ONCE(gsp_phys_gr_mme_prelude_gen, g0);
WRITE_ONCE(gsp_phys_gr_mme_prelude_h,
req->h_object);
- pr_info("vgsp-gr: MME-PRELUDE emitted gen=%u words=%u window=%u h=0x%x push=0x%llx sdm_drop=%u\n",
- g0, pwords, win3d_n, req->h_object,
- req->push_va, sdrop);
+ pr_info("vgsp-gr: MME-PRELUDE emitted gen=%u words=%u window=%u h=0x%x push=0x%llx sdm_drop=%u cap=%u\n",
+ g0, pl_n, win3d_n, req->h_object,
+ req->push_va, sdrop, block_cap);
/*
* SESSION 153-CONTINUED-70: one full dump of the
* replayed MME context-setup program per boot
@@ -18128,9 +18252,14 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
sj, sa_ent[sj],
gsp_sema_mme_ir_covered(sa_ent[sj]));
}
+ } else if (pre_done) {
+ pr_info("vgsp-gr: MME-PRELUDE copy raced an append (gen %u->%u); will re-emit next launch\n",
+ g0, g1);
} else {
- pr_info("vgsp-gr: MME-PRELUDE copy raced an append (gen %u->%u); emitted words=%u, will re-emit next launch\n",
- g0, g1, pl_n);
+ pr_info("vgsp-gr: MME-PRELUDE part gen=%u off=%u words=%u/%u window=%u h=0x%x push=0x%llx sdm_drop=%u cap=%u (continuation next launch)\n",
+ g0, doff, pwords, pl_n, win3d_n,
+ req->h_object, req->push_va, sdrop,
+ block_cap);
}
}
/*
@@ -18237,10 +18366,20 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
*/
if (attr_pre && attr_pre_n &&
READ_ONCE(gsp_phys_rmcall_gr_attr_prelude)) {
- u32 avail = GSP_PHYS_RMCALL_GR_METHOD_WORDS -
+ u32 avail = block_cap -
(u32)(p - pb) - (win3d_n + 2u + 8u);
u32 off, copied = 0;
+ /*
+ * SESSION 153-CONTINUED-79: the attr prelude shares
+ * the same per-launch block cap (see
+ * sema_gl_mme_block_cap); unsigned underflow would
+ * hand it the whole module buffer on an oversized
+ * window.
+ */
+ if ((u32)(p - pb) + win3d_n + 2u + 8u >= block_cap)
+ avail = 0;
+
if (gsp_phys_gr_attr_emit_gen !=
READ_ONCE(gsp_phys_gr_attr_pre_gen)) {
WRITE_ONCE(gsp_phys_gr_attr_emit_gen,
@@ -24449,6 +24588,13 @@ gr_page_unmapped:
* pre-retire - the r1110 mme_pc=513 class).
*/
WRITE_ONCE(gsp_phys_gr_mme_prelude_gen, 0);
+ /*
+ * SESSION 153-CONTINUED-79: also rewind the
+ * split-emission drain cursor, else a cleared
+ * latch with an exhausted cursor would skip
+ * the owed re-preload.
+ */
+ WRITE_ONCE(gsp_phys_gr_mme_pre_emit_off, 0);
pr_warn("vgsp-gr: WEDGE-RECOVER after re-arm grfifo=0x%08x (%s); recovery #%u this boot; MME prelude latch cleared (context re-preload owed)\n",
g1,
(g1 & 0xffff0000u) == 0xbadf0000u ?