summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-01 04:26:35 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-01 04:26:35 -0500
commit604ff3c6c626f797acb890eb6578634c2d597dc6 (patch)
tree17f78274e0aa112e84abb098437f2331117722f5 /kernel
parent3384a396386467489f060f8271de540b8b649891 (diff)
downloadopen-iov-604ff3c6c626f797acb890eb6578634c2d597dc6.tar.gz
open-iov-604ff3c6c626f797acb890eb6578634c2d597dc6.zip
vgsp: store-side emission forensics (DS_HWW_ESR, SPH_INFO_STAGE_START x6+UPPER+REGION, MME_HWW_ESR_INFO, FE_DECODE_STATE, MME shadow-RAM port reads w/ CALL trigger probes) + MME-SA-REARM (re-emit [0x11c]=j,[0x120]=sa_ent[j] for every macro slot the emitted window calls) - root-caused replayed-prelude ordering bug: stream ended SA[34]=0 so every draw call resolved to macro 0; rearm now fires 4/5/9/11/12 slots live; healthy boots DS clean sph unbound=0 (0xa2040a00 lead does NOT reproduce); MME executes macros (pc_valid=1 pc=513 mac=0xf1); calls reach MME (shadow2[c597] 0x3810=00000011) but draw methods NEVER emitted (0xd74=0 0xd78=0 0x1618=0); stores still 0/900-902; win_patch=124:1 knob never reached beef path; next: repair win_patch application point + sweep 124:1 TRACK, strip leading CALL-run header variants, compare CALL-run encoding vs nvk P_1INC shape - SESSION 153 r1229-r1236
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index effff74..5af4acb 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -5103,6 +5103,117 @@ module_param_named(sema_mme_fast_ms, gsp_phys_mme_fast_ms, uint, 0644);
MODULE_PARM_DESC(sema_mme_fast_ms,
"Spin-sample the MME fault registers right after each GR launch doorbell for this many ms, logging every transition before the GSP-RM clears them (0 = off; default 400)");
+/*
+ * SESSION 153-CONTINUED-83: store-side emission forensics.
+ *
+ * The store wall: draws retire but `output retirement wait: 0/N pages
+ * changed` and gen0=0 (no MME-generated method witnessed). The client's
+ * Turing draw is EMITTED BY AN MME MACRO (slot 34 = the draw macro:
+ * BEGIN(0x1618) -> SET_VERTEX_ARRAY_START(0xd74) -> END(0x1614), per the
+ * offline replay of sa_full_stream2.bin and the nvk reference builder), so
+ * "no stores" == "the draw macro never emitted". This probe answers three
+ * questions with one line, at the launch boundary:
+ *
+ * 1. DS_HWW_ESR (0x405840) + the per-stage SPH_INFO snapshot
+ * (0x405c00+si*4 START / 0x405c24+si*4 UPPER / 0x405c1c,c20 REGION):
+ * which pipeline stages failed SPH validation / what VA they fetched.
+ * 2. MME_HWW_ESR_INFO (0x404494) PC + MACRO_ADDRESS + PC_VALID,
+ * INFO_EX (0x4044a4) + IR words INFO2/3/4 (0x40449c/a8/ac): did the
+ * MME actually execute a macro, and where did it stop.
+ * 3. FE_DECODE_STATE_EX(i) (0x40a630+i*4): MME_PC 11:0, MACRO 21:12,
+ * GENERATED 31 - the generated-method witness, all four lanes, at
+ * the launch end (the retire-time read races the release writes).
+ *
+ * Bounded: 24 calls per boot, beef family only, one line per call.
+ */
+/*
+ * SESSION 153-CONTINUED-83: MME shadow-RAM read port (bar0 0x404488 index,
+ * 0x40448c data). The MME tracks class methods in its shadow RAM when the
+ * class's SET_MME_SHADOW_RAM_CONTROL mode selects tracking; reading the
+ * port tells us (a) whether the tracked window's methods ever reached the
+ * MME and (b) what values the MME holds for the draw-relevant methods.
+ * A read is: index = nvclass(15:0) | method_addr(27:16) | READ(30), then
+ * read data. Bounded by the caller; host-side diagnostic only.
+ */
+static u32 gsp_phys_mme_shadow_read(void __iomem *bar0, u32 nvclass, u32 mthd)
+{
+ iowrite32(nvclass | ((mthd & 0xfffu) << 16) | (1u << 30),
+ bar0 + 0x00404488u);
+ return ioread32(bar0 + 0x0040448cu);
+}
+
+static void gsp_phys_store_side_log(void __iomem *bar0, const char *tag,
+ u32 h_object)
+{
+ static u32 ss_n;
+ u32 si, sph[6], sphu[6], rr_a, rr_b, ds, ds2, mminfo, mmex;
+ u32 mm2, mm3, mm4, fex[4], fed[4], fds[4];
+
+ if (!bar0 || ss_n >= 40u)
+ return;
+ ss_n++;
+ for (si = 0; si < 6u; si++) {
+ sph[si] = ioread32(bar0 + 0x00405c00u + si * 4u);
+ sphu[si] = ioread32(bar0 + 0x00405c24u + si * 4u);
+ }
+ for (si = 0; si < 4u; si++) {
+ fex[si] = ioread32(bar0 + 0x0040a630u + si * 4u);
+ fed[si] = ioread32(bar0 + 0x0040a620u + si * 4u);
+ fds[si] = ioread32(bar0 + 0x0040a640u + si * 4u);
+ }
+ rr_a = ioread32(bar0 + 0x00405c1cu);
+ rr_b = ioread32(bar0 + 0x00405c20u);
+ ds = ioread32(bar0 + 0x00405840u);
+ ds2 = ioread32(bar0 + 0x00405848u);
+ mminfo = ioread32(bar0 + 0x00404494u);
+ mmex = ioread32(bar0 + 0x004044a4u);
+ mm2 = ioread32(bar0 + 0x0040449cu);
+ mm3 = ioread32(bar0 + 0x004044a8u);
+ mm4 = ioread32(bar0 + 0x004044acu);
+ pr_info("vgsp-store: %s h=0x%x ds=%08x/%08x sph=%08x,%08x,%08x,%08x,%08x,%08x sphU=%08x,%08x,%08x,%08x,%08x,%08x rr=%08x,%08x\n",
+ tag, h_object, ds, ds2,
+ sph[0], sph[1], sph[2], sph[3], sph[4], sph[5],
+ sphu[0], sphu[1], sphu[2], sphu[3], sphu[4], sphu[5],
+ rr_a, rr_b);
+ pr_info("vgsp-store: %s h=0x%x mme_esr_info=%08x(pcv=%u pc=%u mac=0x%x) ex=%08x ir=%08x,%08x,%08x fed=%08x,%08x,%08x,%08x fex=%08x,%08x,%08x,%08x\n",
+ tag, h_object, mminfo, (mminfo >> 28) & 1u, mminfo & 0xfffu,
+ (mminfo >> 12) & 0xffu, mmex, mm2, mm3, mm4,
+ fed[0], fed[1], fed[2], fed[3],
+ fex[0], fex[1], fex[2], fex[3]);
+ /*
+ * MME shadow-RAM readback for the draw-relevant C597 methods (tracked
+ * methods show the last value the MME saw; zeros = never tracked).
+ * Also probe the MME setup pair and the draw trigger/vertex-start.
+ */
+ pr_info("vgsp-store: %s h=0x%x shadow[c597] 0x114=%08x 0x11c=%08x 0x124=%08x 0x260=%08x 0x840=%08x 0xd74=%08x 0xd78=%08x 0x1618=%08x\n",
+ tag, h_object,
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x114u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x11cu),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x124u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x260u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x840u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0xd74u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0xd78u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x1618u));
+ /*
+ * SESSION 153-CONTINUED-83 probe 2: the CALL trigger methods the
+ * window uses (are the calls even reaching the MME?), a repeat read
+ * (does a read clear?), and the dword-address interpretation of the
+ * draw/RT methods (0xd74>>2, 0x840>>2) to pin the index units.
+ */
+ pr_info("vgsp-store: %s h=0x%x shadow2[c597] 0x3800=%08x 0x3810=%08x 0x3910=%08x 0x3938=%08x 0x3940=%08x 0x840r=%08x 0xd74dw=%08x 0x840dw=%08x 0x1618r=%08x\n",
+ tag, h_object,
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x3800u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x3810u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x3910u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x3938u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x3940u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x840u),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0xd74u >> 2),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x840u >> 2),
+ gsp_phys_mme_shadow_read(bar0, 0xc597u, 0x1618u >> 2));
+}
+
static bool gsp_phys_mme_fast_sample(void __iomem *bar0, const char *tag,
u32 h_object)
{
@@ -5187,6 +5298,16 @@ static bool gsp_phys_mme_fast_sample(void __iomem *bar0, const char *tag,
pr_info("vgsp-gr: MME-FAST end %s h=0x%x events=%u%s\n",
tag, h_object, n, poisoned ? " (poison)" : "");
/*
+ * SESSION 153-CONTINUED-83 store-side emission forensics: right after
+ * the launch's retire spin, snapshot the DS shader-program-header
+ * latches (which pipeline stages failed SPH validation), the MME
+ * execution state (did the MME run a macro, and where is its PC), and
+ * the FE decode-state EX slots (did any method decode carry the MME
+ * GENERATED bit). Bounded per boot (beef-family only).
+ */
+ if ((h_object & 0xfffff000u) == 0xbeef0000u)
+ gsp_phys_store_side_log(bar0, tag, h_object);
+ /*
* SESSION 153-CONTINUED-72: return the poison observation to the
* launch site. The r1149 race: the poison flooded during this spin
* and the FECS cleared it before the poll loop's WEDGE-RECOVER check
@@ -18613,6 +18734,57 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
memcpy(p, win3d, (size_t)win3d_n * 4);
p += win3d_n;
}
+ /*
+ * SESSION 153-CONTINUED-83: SA re-arm. The captured prelude can
+ * end with a later client push's SA-pointer write that re-points
+ * a slot the window still calls (r1231: the prelude's LAST SA
+ * write is SA[34]=0 while its earlier write SA[34]=0x265 names
+ * the draw macro - BEGIN/SET_VERTEX_ARRAY_START/END, per the
+ * offline replay of the captured SA stream - so every
+ * CALL_MME_MACRO(34) would resolve to IR entry 0). The capture
+ * re-emits pushes in first-encounter order, so the late zeroing
+ * clobbers the entry the window's call needs. Re-emit
+ * SA[slot]=entry for every slot the emitted window calls, from
+ * the captured SA table, so the calls resolve to the macros the
+ * capture proved. Bounded: one 3-word run per called slot.
+ */
+ {
+ u32 sa_ent[64];
+ u64 sa_mask = gsp_sema_mme_sa_get(sa_ent, 64);
+ u32 r = 0, rearm = 0;
+
+ while (r < win3d_n && rearm < 32u) {
+ u32 h = win3d[r];
+ u32 op = (h >> 29) & 7u;
+ u32 cnt = (h >> 16) & 0xfffu;
+ u32 span = ((op == 1u || op == 3u ||
+ op == 5u) && cnt &&
+ r + 1u + cnt <= win3d_n) ?
+ 1u + cnt : 1u;
+ u32 mb = (h & 0xfffu) << 2;
+
+ if (mb >= 0x3800u && mb <= 0x39fcu) {
+ u32 j = (mb - 0x3800u) / 8u;
+
+ if (j < 64u &&
+ (sa_mask & (1ull << j)) &&
+ sa_ent[j]) {
+ *p++ = ((u32)
+ GSP_PHYS_RMCALL_METHOD_IMM
+ << 29) |
+ (2u << 16) |
+ (0x11cu >> 2);
+ *p++ = j;
+ *p++ = sa_ent[j];
+ rearm++;
+ }
+ }
+ r += span;
+ }
+ if (rearm)
+ pr_info("vgsp-gr: MME-SA-REARM %u slot(s) re-pointed before the window (h=0x%x push=0x%llx)\n",
+ rearm, req->h_object, req->push_va);
+ }
p = gsp_phys_rmcall_push_gr(p,
GSP_PHYS_RMCALL_GR_SET_REPORT_SEMAPHORE_A,
(u32)(sem_va >> 32));
@@ -26009,6 +26181,18 @@ gr_page_unmapped:
late, late_tracked,
late ? "LATE-STORES - copy-out will ship them" :
"NO-STORES - dispatch lost or read-only kernel");
+ /*
+ * SESSION 153-CONTINUED-83: the no-writes moment
+ * is the store wall's fingerprint - snapshot the
+ * DS/SPH/MME/FE-decode evidence here so the
+ * stage that never received a program header (or
+ * the MME PC that never emitted the draw) is on
+ * the same line as the failing launch.
+ */
+ if (!late)
+ gsp_phys_store_side_log(gsp_phys_gpu_bar0(),
+ "no-writes",
+ req->h_object);
}
if (qmd_rel_hpa) {