summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-31 03:20:57 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-31 03:20:57 -0400
commit6a48a4a2420cfe3171a135fe7621ec16967d2021 (patch)
tree08f445a4a2558101c83f720dbad20189471fb995 /kernel/gsp_phys_booter.c
parent667491fe59737ebfb327804d361b2eb0a8b170bb (diff)
downloadopen-iov-6a48a4a2420cfe3171a135fe7621ec16967d2021.tar.gz
open-iov-6a48a4a2420cfe3171a135fe7621ec16967d2021.zip
vgsp+diag: attr/pipeline prelude (families 0x1100-0x1200/0x2000-0x2060, dedup, 512w, program-pair VA record; emitted via patch_window relocation, run-aligned after MME prelude), mature-prelude gate (>=64 0x114 code words, sema_gr_prelude_gate_ms=60000 busy-defer), pin_gr_stream 0.75s pass, trap regs in sked sampler - first clean DS+MME (ds_esr=80000000 mme_esr=80000000, a2040a00 gone); 0x1168 CLASS ERROR persists as MME-MACRO-GENERATED WRITE (no 0x1168 header in emitted stream; macro(2) args [0,0,600000,0,610800]); next: disassemble macro (2) at pc 0xa + trapped-addr read pre-latch - SESSION 153 r1095-r1100
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c177
1 files changed, 170 insertions, 7 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 3bbcf45..42fcdb1 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -17130,6 +17130,43 @@ MODULE_PARM_DESC(sema_gl_mme_prelude,
"Preplay the captured client MME context-setup runs once per capture generation ahead of the first 3D window replay (default 1)");
/*
+ * SESSION 153-CONTINUED-57: attr/pipeline state prelude. The r1091
+ * full-MME-prelude boot cleared MME (mme_esr=80000000) but the first beef
+ * window then latched a draw-shader program-header error
+ * (NV_PGRAPH_PRI_DS_HWW_ESR 0x405840 = 0xa2040a00: SPH9|SPH11|SPH18,
+ * M_PIPE_STAGE = VSB|PS) and a class error at SET_VERTEX_ATTRIBUTE_A(2)
+ * (0x1168, INVALID_ENUM): the replayed window is a mid-stream state cut -
+ * the attribute/pipeline record the client set in EARLIER windows (the
+ * missing stages' SET_PIPELINE_PROGRAM_ADDRESS binds and the attribute
+ * format state) was never replayed, so the DS validated program headers
+ * that were never bound. With this knob the launch builder preplays the
+ * captured runs from the service's attr prelude buffer (see
+ * svc_attr_prelude_capture), relocated exactly like the window itself
+ * (the patched copy is computed by the caller - it needs the launch page
+ * set and the live shadow counter), run-aligned, drained across the first
+ * launches of a capture generation. Declared before build_gr_launch (its
+ * reader); the matching capture-side knob is sema_attr_prelude_cap.
+ * Default 1; A/B with 0.
+ */
+static bool gsp_phys_rmcall_gr_attr_prelude = true;
+module_param_named(sema_gl_attr_prelude, gsp_phys_rmcall_gr_attr_prelude,
+ bool, 0644);
+MODULE_PARM_DESC(sema_gl_attr_prelude,
+ "Preplay the captured client attr/pipeline runs (0x1100..0x11fc, 0x2000..0x205c, relocation applied) ahead of the first 3D window replays of a capture generation (default 1)");
+
+/*
+ * The patched (relocation-applied) attr prelude for the current capture
+ * generation, built by the submit path just before build_gr_launch. Single
+ * caller (the ordered single-inflight sema work item), so plain statics.
+ */
+#define GSP_PHYS_GR_ATTR_PRE_WORDS 512u
+static u32 gsp_phys_gr_attr_pre[GSP_PHYS_GR_ATTR_PRE_WORDS];
+static u32 gsp_phys_gr_attr_pre_n;
+static u32 gsp_phys_gr_attr_pre_gen; /* capture gen the patch is from */
+static u32 gsp_phys_gr_attr_emit_gen; /* gen whose runs are draining */
+static u32 gsp_phys_gr_attr_emit_off; /* word cursor into attr_pre */
+
+/*
* GR launch method block: the inline QMD run at its original shape and the
* channel REPORT_SEMAPHORE release. The stock guest push does NOT emit
* SET_OBJECT before the inline run (the compute class is bound on the
@@ -17140,7 +17177,9 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
const struct gsp_phys_gr_submit *req,
const u32 *qmd, u64 qmd_va,
u64 sem_va, u32 sem_payload,
- const u32 *win3d, u32 win3d_n)
+ const u32 *win3d, u32 win3d_n,
+ const u32 *attr_pre,
+ u32 attr_pre_n)
{
u32 *p = pb;
int prelude = gsp_phys_rmcall_gr_prelude_value();
@@ -17214,6 +17253,66 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
g0, g1, pl_n);
}
}
+ /*
+ * SESSION 153-CONTINUED-57: attr/pipeline state prelude (see the
+ * sema_gl_attr_prelude knob above). Emit the patched captured
+ * runs after the MME prelude and ahead of the window,
+ * run-aligned, draining across launches when the remaining
+ * block budget cannot take the whole remainder. The cursor
+ * resets when a new capture generation is patched. A window
+ * with no room at all defers the whole step to the next launch
+ * (logged by the patch site).
+ */
+ if (attr_pre && attr_pre_n &&
+ READ_ONCE(gsp_phys_rmcall_gr_attr_prelude)) {
+ u32 avail = GSP_PHYS_RMCALL_GR_METHOD_WORDS -
+ (u32)(p - pb) - (win3d_n + 2u + 8u);
+ u32 off, copied = 0;
+
+ if (gsp_phys_gr_attr_emit_gen !=
+ READ_ONCE(gsp_phys_gr_attr_pre_gen)) {
+ WRITE_ONCE(gsp_phys_gr_attr_emit_gen,
+ READ_ONCE(gsp_phys_gr_attr_pre_gen));
+ WRITE_ONCE(gsp_phys_gr_attr_emit_off, 0);
+ }
+ off = READ_ONCE(gsp_phys_gr_attr_emit_off);
+ while (off < attr_pre_n) {
+ u32 hdr = attr_pre[off];
+ u32 op = (hdr >> 29) & 7u;
+ u32 cnt = (hdr >> 16) & 0xfffu;
+ u32 span = ((op == 1u || op == 3u ||
+ op == 5u) && cnt) ?
+ 1u + cnt : 1u;
+
+ if (off + span > attr_pre_n)
+ span = attr_pre_n - off;
+ if (copied + span > avail)
+ break;
+ memcpy(&p[copied], &attr_pre[off],
+ (size_t)span * 4u);
+ copied += span;
+ off += span;
+ }
+ if (copied) {
+ p += copied;
+ WRITE_ONCE(gsp_phys_gr_attr_emit_off, off);
+ pr_info("vgsp-gr: ATTR-PRELUDE emitted gen=%u words=%u/%u window=%u h=0x%x push=0x%llx%s\n",
+ READ_ONCE(gsp_phys_gr_attr_pre_gen),
+ off, attr_pre_n, win3d_n,
+ req->h_object, req->push_va,
+ off < attr_pre_n ?
+ " (continuation next launch)" : "");
+ } else if (off < attr_pre_n) {
+ static u32 attr_defer_log;
+
+ if (attr_defer_log < 8) {
+ attr_defer_log++;
+ pr_info("vgsp-gr: ATTR-PRELUDE deferred (no room: window=%u avail=%u) h=0x%x\n",
+ win3d_n, avail,
+ req->h_object);
+ }
+ }
+ }
memcpy(p, win3d, (size_t)win3d_n * 4);
p += win3d_n;
p = gsp_phys_rmcall_push_gr(p,
@@ -20629,8 +20728,8 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
u32 qmd_rel_off = 0, ch_rel_off = 0;
u32 poll = 0, w0 = 0, w1 = 0, grpoll_n = 0;
bool sem_gated = false;
- static u32 sked_prev[20];
- static u32 sked_sample[20];
+ static u32 sked_prev[24];
+ static u32 sked_sample[24];
static u32 sked_tick;
static bool sked_first;
/*
@@ -21865,6 +21964,41 @@ gr_page_unmapped:
pr_info("vgsp-gr: 3D window relocated %u operand pair(s) to shadow VAs (window=%u shadow=%u dropped=%u subdrop=%u)\n",
nrel, win3d_n, n_shadow, ndrop,
gsp_phys_rmcall_gr_3d_last_subdrop);
+ /*
+ * SESSION 153-CONTINUED-57: patch the attr/pipeline prelude for
+ * this launch (relocation exactly like the window: the
+ * SET_PIPELINE_PROGRAM_ADDRESS pairs and any other recognised
+ * operand land in engine-visible shadow VAs; sub!=0 and
+ * win_drop runs are removed by the same pass). Only done when
+ * the capture generation moved - the shadow VAs are stable
+ * per HPA for the boot, so an older patch stays valid while it
+ * drains across launches. See gsp_phys_gr_attr_pre*.
+ */
+ if (READ_ONCE(gsp_phys_rmcall_gr_attr_prelude)) {
+ const u32 *ap;
+ u32 apn = 0, apg = 0;
+
+ ap = gsp_sema_attr_prelude_get(&apn, &apg);
+ if (ap && apn && apg &&
+ apg != READ_ONCE(gsp_phys_gr_attr_pre_gen)) {
+ u32 adrop = 0, an = apn;
+
+ if (an > GSP_PHYS_GR_ATTR_PRE_WORDS)
+ an = GSP_PHYS_GR_ATTR_PRE_WORDS;
+ gsp_phys_rmcall_gr_3d_patch_window(ap, an,
+ gsp_phys_gr_attr_pre,
+ &gsp_phys_gr_attr_pre_n,
+ &adrop, req, &n_shadow);
+ if (gsp_phys_gr_attr_pre_n) {
+ WRITE_ONCE(gsp_phys_gr_attr_pre_gen,
+ apg);
+ pr_info("vgsp-gr: ATTR-PRELUDE patched gen=%u raw=%u kept=%u dropped=%u h=0x%x push=0x%llx\n",
+ apg, an, gsp_phys_gr_attr_pre_n,
+ adrop, req->h_object,
+ req->push_va);
+ }
+ }
+ }
if (ndrop) {
static u32 gr3d_drop_log;
@@ -21950,7 +22084,9 @@ gr_page_unmapped:
words = gsp_phys_rmcall_build_gr_launch(methods, req, qmd,
qmd_dst,
ch_sem_va, want_ch,
- win3d, win3d_n);
+ win3d, win3d_n,
+ gsp_phys_gr_attr_pre,
+ gsp_phys_gr_attr_pre_n);
memcpy(gsp_phys_chunk_page_va(pb, 0), methods, words * 4);
/* SESSION 153-CONTINUED-12: identify this block to a later PBDMA dump. */
WRITE_ONCE(gsp_phys_gr_last_words, words);
@@ -22427,10 +22563,28 @@ gr_page_unmapped:
*/
sked_sample[18] = ioread32(bar0 + 0x004000c0u);
sked_sample[19] = ioread32(bar0 + 0x004000c4u);
+ /*
+ * SESSION 153-CONTINUED-57: the class-error trapped
+ * register set (gr_error_gk104.c grGetExceptionChannel):
+ * NV_PGRAPH_TRAPPED_ADDR 0x40704 (MTHD offset + SUBCH +
+ * INVALID status bit), TRAPPED_DATA_LOW 0x40708 (the
+ * class error's "Data" field), TRAPPED_DATA_HIGH
+ * 0x4070c, and TRAPPED_DATA_MME 0x40710 (PC 11:0 +
+ * MACRO_ADDRESS 19:12) - the last one names whether the
+ * offending write came from MME macro execution. The
+ * real RM clears these within ~ms of the fault; a
+ * per-tick sample catches the first change. The
+ * persistent 0x1168/Data=0 class error (r1091/r1098)
+ * needs exactly this decode.
+ */
+ sked_sample[20] = ioread32(bar0 + 0x00400704u);
+ sked_sample[21] = ioread32(bar0 + 0x00400708u);
+ sked_sample[22] = ioread32(bar0 + 0x0040070cu);
+ sked_sample[23] = ioread32(bar0 + 0x00400710u);
if (sked_first ||
memcmp(sked_sample, sked_prev,
sizeof(sked_sample))) {
- pr_info("vgsp-gr: sked rec +%ums cwd0=%08x cwd1=%08x cwd2=%08x info1=%08x info2=%08x act=%08x esr=%08x grfifo=%08x fecs_cur=%08x fecs_new=%08x ctxsw1=%08x fe0=%08x fehost=%08x fecsirq=%08x ds_esr=%08x mme_esr=%08x mme_pc=%u mme_mac=0x%x mme_ir=%08x mth0=%08x mth1=%08x(pbaddr=0x%x sub=%u incr=%u)\n",
+ pr_info("vgsp-gr: sked rec +%ums cwd0=%08x cwd1=%08x cwd2=%08x info1=%08x info2=%08x act=%08x esr=%08x grfifo=%08x fecs_cur=%08x fecs_new=%08x ctxsw1=%08x fe0=%08x fehost=%08x fecsirq=%08x ds_esr=%08x mme_esr=%08x mme_pc=%u mme_mac=0x%x mme_ir=%08x mth0=%08x mth1=%08x(pbaddr=0x%x sub=%u incr=%u) trap=%08x(data_lo=%08x hi=%08x sub=%u mmegen=%u dhv=%u) mmepc=%u mmemac=0x%x\n",
sked_tick *
GSP_PHYS_RMCALL_POLL_MS,
sked_sample[0], sked_sample[1],
@@ -22447,7 +22601,14 @@ gr_page_unmapped:
sked_sample[18], sked_sample[19],
(sked_sample[18] >> 2) << 2,
(sked_sample[18] >> 16) & 7u,
- sked_sample[18] & 1u);
+ sked_sample[18] & 1u,
+ sked_sample[20], sked_sample[21],
+ sked_sample[22],
+ (sked_sample[20] >> 16) & 7u,
+ (sked_sample[20] >> 20) & 1u,
+ (sked_sample[20] >> 24) & 1u,
+ sked_sample[23] & 0xfffu,
+ (sked_sample[23] >> 12) & 0xffu);
memcpy(sked_prev, sked_sample,
sizeof(sked_sample));
sked_first = false;
@@ -23372,7 +23533,9 @@ gr_page_unmapped:
methods, req, qmd,
qmd_dst, ch_sem_va,
want_ch, win3d,
- win3d_n);
+ win3d_n,
+ gsp_phys_gr_attr_pre,
+ gsp_phys_gr_attr_pre_n);
memcpy(gsp_phys_chunk_page_va(pb, 0),
methods, words * 4);
}