summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-01 22:26:10 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-01 22:26:10 -0500
commitbf08d2dc18e419bb70e515eaaa8dd9684bb08ffc (patch)
tree4a1ee5dd69ed81e12f786a54961b5093117d1f89
parentd61bf4e99e5119f7a6b8ee43e745fbbf4fd5c4ef (diff)
downloadopen-iov-bf08d2dc18e419bb70e515eaaa8dd9684bb08ffc.tar.gz
open-iov-bf08d2dc18e419bb70e515eaaa8dd9684bb08ffc.zip
vgsp: CONT-103 - TWO ROOT CAUSES FOUND: (1) '(engine fetch NONE)' was an ARTIFACT - qmd_dst_mem never set for stream3d (all three sites !stream3d-guarded 25707/25733/25741) so the sentinel test was vacuous; GP_GET proves the engine fetches (FETCH-WIT h=0xbeef0100 slot=4 gpget 4->5 engine-fetched); (2) DEADLOCK: calls-kept launch was 2126-2142 words (1613-word prelude re-emit) > CONT-79 ~2050-wall so it never started (r1345/47/48 begin grfifo=00000001 events=0 timeout) - FIXES: sema_gl_mme_prelude_live_skip (default 1; skip forced 1613-word prelude re-emission once the generation's final part was carried by an engine-executed launch; live-gen set at poll break only when GP_GET advanced, cleared on timeout) + sema_gl_mme_nop_pair (default 0; elide program-pair runs method space [0x2054,0x2158]) + FETCH-WIT instrumentation (poll break/timeout gpget A->B engine-fetched, gpget/gpput in GR LAUNCH submitted, honest 'engine fetch n/a (no QMD deposit...sentinel vacuous)' wording); r1356 fix1: words=500, launch starts (FETCH-WIT timeout slot=6 gpget 6->7) then traps CONT-101 pair trap=80002058 data=019a0900; r1357 fix1+2: MME-PAIR-DROP 25 word(s) window=386->361, words=475, 0x2058 gone, FE advances to CALL runs: trap=80102390 data=00000005 (mmegen=1) park grfifo 0f0f1602->00000001 = FIRST MME-GENERATED METHOD WRITE AT THE WALL; GATE1 black 0/900 pages - next: FE rejects first MME-generated method 0x2390 (mmegen=1 data=5): identify 0x2390 role (macro-port family; check MME-WINRUN/3D win dumps + mmeref + direct lane h=0x1000013) and why generated write traps (CONT-80: bare DATA/macro-port write without open macro context parks; generated port may need macro context conserved); keep mode stays OFF - SESSION 153 r1356-r1357
-rw-r--r--kernel/gsp_phys_booter.c171
1 files changed, 162 insertions, 9 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 663f276..eada9ae 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -17980,6 +17980,47 @@ static u32 gsp_phys_gr_mme_pre_emit_h;
static u32 gsp_phys_gr_mme_pre_emit_off;
/*
+ * CONT-103: prelude residency witness + calls-kept block shrink.
+ * The CONT-79 split-emission re-carries the whole prelude prefix on EVERY
+ * launch while keep_mask is set (idempotent re-emission, CONT-72), so the
+ * first calls-kept launch is 1613 prelude words + the 410-word window =
+ * 2126-2142 words - over the ~2050-word fetch wall (CONT-79: oversized
+ * blocks never start, PBDMA parks). The deadlock: the calls can only run
+ * after the program is resident, and the launch that would run them is too
+ * big to start. The re-emission is only needed while the program is NOT
+ * known resident; the launch that carries the final part is the witness
+ * (its poll break with GP_GET advanced proves the engine consumed it).
+ * live_gen records the generation whose carrier executed; while it equals
+ * the capture generation the drain restart is skipped and the calls-kept
+ * launch ships window-only (~530 words, well under the wall).
+ * sema_gl_mme_prelude_live_skip=0 restores the unconditional re-emission
+ * for a one-flip A/B.
+ */
+static u32 gsp_phys_gr_mme_pending_gen; /* final part carried by the last
+ * launch; consumed at its poll */
+static u32 gsp_phys_gr_mme_live_gen; /* generation whose carrier executed */
+static bool gsp_phys_rmcall_gr_mme_live_skip = true;
+module_param_named(sema_gl_mme_prelude_live_skip,
+ gsp_phys_rmcall_gr_mme_live_skip, bool, 0644);
+MODULE_PARM_DESC(sema_gl_mme_prelude_live_skip,
+ "Skip the forced per-launch prelude re-emission once the generation's final part has been carried by a launch the engine executed (default 1; 0 = always re-emit, pre-CONT-103 behavior)");
+
+/*
+ * CONT-103: elide the program-address pair runs (method space
+ * [0x2054, 0x2158]) from a calls-kept window. With the prelude-live skip the
+ * calls-kept launch starts, and the engine then traps 0x80002058 on the
+ * relocated (shadow-pool) pair operand and parks - the CONT-101 trap class.
+ * The binds persist on the channel from the earlier calls-held launches, so
+ * dropping the re-binds removes the trapping write; the calls and the MME
+ * program stay. Off by default: the A/B against the trapping state.
+ */
+static bool gsp_phys_rmcall_gr_mme_nop_pair;
+module_param_named(sema_gl_mme_nop_pair, gsp_phys_rmcall_gr_mme_nop_pair,
+ bool, 0644);
+MODULE_PARM_DESC(sema_gl_mme_nop_pair,
+ "Elide program-address pair runs (0x2054/0x2094/0x2154 families) from a calls-kept 3D window (default 0; the engine traps 0x2058 on the relocated shadow operand)");
+
+/*
* 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
@@ -18945,7 +18986,11 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
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) ||
+ ((READ_ONCE(gsp_phys_rmcall_gr_keep_mask) &&
+ !(READ_ONCE(
+ gsp_phys_rmcall_gr_mme_live_skip) &&
+ READ_ONCE(gsp_phys_gr_mme_live_gen) ==
+ pl_gen)) ||
pl_gen != READ_ONCE(
gsp_phys_gr_mme_prelude_gen)))) {
WRITE_ONCE(gsp_phys_gr_mme_pre_emit_gen,
@@ -19446,6 +19491,10 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
WRITE_ONCE(gsp_phys_gr_mme_prelude_gen, g0);
WRITE_ONCE(gsp_phys_gr_mme_prelude_h,
req->h_object);
+ /* CONT-103: this launch carries the final
+ * part; its poll outcome (executed or not)
+ * decides whether the program is live. */
+ WRITE_ONCE(gsp_phys_gr_mme_pending_gen, g0);
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);
@@ -19813,6 +19862,54 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
held, pl_gen, req->h_object,
win3d_n, w, req->push_va);
p += w;
+ } else if (READ_ONCE(gsp_phys_rmcall_gr_mme_nop_pair)) {
+ /*
+ * CONT-103: the calls-kept launch now starts (the
+ * prelude-live skip shrank it under the ~2050-word
+ * wall) and the engine decodes the window, but the
+ * FE then TRAPS on the relocated program-address
+ * pair write (trap=0x80002058 data=<shadow VA>,
+ * CONT-101: the relocated 0x2054-pair operand) and
+ * parks the front-end (grfifo 00000001). The binds
+ * persist on the channel from the earlier
+ * calls-held launches of the same capture, so
+ * eliding the pair re-binds removes the trapping
+ * write while keeping the program bound. Drops any
+ * method run overlapping the program-pair space
+ * [0x2054, 0x2158] (0x2054/0x2058, 0x2094/0x2098,
+ * 0x2154/0x2158 - the client window's own pairs and
+ * the synthesized SPH binds alike; this walk runs on
+ * the final window, prepends included).
+ */
+ u32 r = 0, w = 0, elided = 0;
+
+ while (r < win3d_n) {
+ u32 h = win3d[r];
+ u32 op = (h >> 29) & 7u;
+ u32 cnt = (h >> 16) & 0xfffu;
+ u32 span = 1u, m0, mend;
+
+ if ((op == 1u || op == 3u || op == 5u) &&
+ cnt && r + 1u + cnt <= win3d_n)
+ span = 1u + cnt;
+ m0 = (h & 0xfffu) << 2;
+ mend = m0 + 4u * (span - 1u);
+ if ((op == 0u || op == 1u || op == 3u ||
+ op == 4u || op == 5u) &&
+ m0 <= 0x2158u && mend >= 0x2054u) {
+ elided += span;
+ r += span;
+ continue;
+ }
+ memcpy(&p[w], &win3d[r], (size_t)span * 4u);
+ w += span;
+ r += span;
+ }
+ if (elided)
+ pr_info("vgsp-gr: MME-PAIR-DROP %u word(s) of program-pair runs elided (calls-kept launch; binds persist from the held-call launches) h=0x%x push=0x%llx window=%u->%u\n",
+ elided, req->h_object, req->push_va,
+ win3d_n, w);
+ p += w;
} else {
memcpy(p, win3d, (size_t)win3d_n * 4);
p += win3d_n;
@@ -21767,7 +21864,8 @@ static bool gsp_phys_gr_win0_retry_rearm(u32 *qmd,
*/
static noinline void
gsp_phys_gr_poll_break_log(u32 w0, u32 want_qmd, u32 w1, u32 since_us,
- const struct gsp_phys_rmcall_ce_submit *sub)
+ const struct gsp_phys_rmcall_ce_submit *sub,
+ u32 h_object)
{
struct gsp_phys_boot_chunk *ud_c =
&boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_USERD];
@@ -21796,11 +21894,53 @@ gsp_phys_gr_poll_break_log(u32 w0, u32 want_qmd, u32 w1, u32 since_us,
(u32)ktime_to_us(ktime_get()) - since_us,
usr_gpget, sub->gpget, sub->gpput,
sub->slot, re0, re1, sub->e0, sub->e1);
+ /*
+ * CONT-103: engine-fetch witness + prelude-liveness bookkeeping.
+ * GP_GET advancing past the published slot is the PBDMA consuming
+ * this launch's GPFIFO entry - the fetch witness the QMD sentinel
+ * cannot provide on the stream3d lane (no QMD deposit there). A
+ * break with GP_GET frozen is a stale/software-authored release.
+ */
+ pr_info("vgsp-gr: FETCH-WIT h=0x%x slot=%u gpget %u->%u %s\n",
+ h_object, sub->slot, sub->gpget, usr_gpget,
+ usr_gpget != sub->gpget ? "engine-fetched" :
+ "GP_GET-frozen (software ack)");
+ if (usr_gpget != sub->gpget &&
+ READ_ONCE(gsp_phys_gr_mme_pending_gen)) {
+ WRITE_ONCE(gsp_phys_gr_mme_live_gen,
+ READ_ONCE(gsp_phys_gr_mme_pending_gen));
+ WRITE_ONCE(gsp_phys_gr_mme_pending_gen, 0);
+ }
/* r425: the healthy-launch SKED/FECS baseline for the wedge compare. */
gsp_phys_gr_sked_wit(gsp_phys_gpu_bar0(), "post-poll");
}
/*
+ * CONT-103: fetch-witness for a launch that did NOT break - GP_GET frozen
+ * means the PBDMA never consumed the entry (the >2050-word fetch wall /
+ * parked front-end class), so the carrier's generation is not live and the
+ * next launch must re-emit the prelude. noinline: keeps the submit frame.
+ */
+static noinline void
+gsp_phys_gr_fetch_miss_log(u32 h_object,
+ const struct gsp_phys_rmcall_ce_submit *sub,
+ const char *tag)
+{
+ struct gsp_phys_boot_chunk *ud_c =
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_USERD];
+ u8 *ud = ud_c->pages ? gsp_phys_chunk_page_va(ud_c, 0) : NULL;
+ u32 usr_gpget = ud ?
+ get_unaligned_le32(ud + gsp_phys_rmcall_userd_ctl_off() +
+ GSP_PHYS_RMCALL_USERD_GPGET_OFF) : 0;
+
+ pr_info("vgsp-gr: FETCH-WIT %s h=0x%x slot=%u gpget %u->%u %s\n",
+ tag, h_object, sub->slot, sub->gpget, usr_gpget,
+ usr_gpget != sub->gpget ? "engine-fetched" :
+ "GP_GET-frozen (NOT fetched: parked or over-cap block)");
+ WRITE_ONCE(gsp_phys_gr_mme_pending_gen, 0);
+}
+
+/*
* SESSION 153-CONTINUED-72: GR-STATE retire readback. The keep-mask A/B
* must answer "does the kept macro execute at all" before chasing the
* 0/903 stores. The FE decode-state EX records (0x40a630..3c) name the
@@ -26746,9 +26886,9 @@ gr_page_unmapped:
break;
}
}
- pr_info("vgsp-gr: GR LAUNCH submitted h=0x%x push=0x%llx len=%u pages=%u shadow=%u qmd_va=0x%llx slot=%u words=%u e0=0x%08x e1=0x%08x prelude=%d qmdvirt=%d token=0x%x; polling qmd_rel=%u ch_rel=0x%08x (<=%u ms)%s\n",
+ pr_info("vgsp-gr: GR LAUNCH submitted h=0x%x push=0x%llx len=%u pages=%u shadow=%u qmd_va=0x%llx slot=%u gpget=%u gpput=%u words=%u e0=0x%08x e1=0x%08x prelude=%d qmdvirt=%d token=0x%x; polling qmd_rel=%u ch_rel=0x%08x (<=%u ms)%s\n",
req->h_object, req->push_va, req->push_len, req->n_pages,
- n_shadow, req->qmd_va, sub.slot, words,
+ n_shadow, req->qmd_va, sub.slot, sub.gpget, sub.gpput, words,
sub.e0, sub.e1,
gsp_phys_rmcall_gr_prelude_value(),
gsp_phys_rmcall_gr_qmdvirt_value(),
@@ -27118,7 +27258,8 @@ gr_page_unmapped:
if ((!qmd_rel || w0 == want_qmd) && w1 == want_ch) {
/* F4-a: first poll break + USERD witnesses. */
gsp_phys_gr_poll_break_log(w0, want_qmd, w1,
- poll_start_us, &sub);
+ poll_start_us, &sub,
+ req->h_object);
/*
* SESSION 153-CONTINUED-72: GR-STATE readback at the
* retire (fed MME-generated-write records + latches).
@@ -27142,6 +27283,8 @@ gr_page_unmapped:
w0, want_qmd, w1, want_ch, req->h_object,
req->push_va);
gsp_phys_mme_regs_log(bar0, "wait-max");
+ gsp_phys_gr_fetch_miss_log(req->h_object, &sub,
+ "wait-max");
ret = -ETIMEDOUT;
goto out;
}
@@ -27154,6 +27297,8 @@ gr_page_unmapped:
poll_ms, w0, want_qmd, w1,
want_ch, req->h_object, req->push_va);
gsp_phys_mme_regs_log(bar0, "timeout");
+ gsp_phys_gr_fetch_miss_log(req->h_object, &sub,
+ "timeout");
/*
* F4-b: one-shot deposit readback at the FIRST timeout
* (the old post-mortem only ran after attempt 3, which
@@ -27702,9 +27847,16 @@ gr_page_unmapped:
if (wrote == 0 && n_tracked) {
bool ff = gsp_phys_gr_qmd_fetched(qmd_dst_mem);
- pr_info("vgsp-gr: first-attempt witness: engine fetch %s (qmd sentinel %s) tracked=%u\n",
- ff ? "OK" : "NONE",
- ff ? "overwritten" : "intact", n_tracked);
+ /* CONT-103: no QMD deposit on the stream3d lane, so the
+ * sentinel is vacuous there; the GP_GET FETCH-WIT is the
+ * fetch witness for that lane. */
+ if (qmd_dst_mem)
+ pr_info("vgsp-gr: first-attempt witness: engine fetch %s (qmd sentinel %s) tracked=%u\n",
+ ff ? "OK" : "NONE",
+ ff ? "overwritten" : "intact", n_tracked);
+ else
+ pr_info("vgsp-gr: first-attempt witness: engine fetch n/a (no QMD deposit on this lane - sentinel vacuous; see FETCH-WIT) tracked=%u\n",
+ n_tracked);
}
/*
* r427 idempotent fast-accept: a zero-write launch whose identity
@@ -28141,7 +28293,8 @@ gr_page_unmapped:
fetched ? "AMBIGUOUS" : "CONFIRMED",
req->h_object, req->push_va, req->n_data,
n_tracked, nw_attempts, want_qmd,
- fetched ? "OK" : "NONE",
+ qmd_dst_mem ? (fetched ? "OK" : "NONE") :
+ "n/a(noQMD-stream3d)",
READ_ONCE(gsp_phys_gr_nw_streak) + 1u,
gsp_phys_gr_wedge_quiet,
gsp_phys_gr_wedge_heals);