summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-29 08:30:32 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-29 08:30:32 -0400
commitaf37d9766c5fe4e256e07faefa095535ba4c993c (patch)
tree277840997d0cb79fad1e3ec0d94a3e38af2a57fb /kernel
parent94a0f3de36a113b350ec9a86e11909c1684acdc4 (diff)
downloadopen-iov-af37d9766c5fe4e256e07faefa095535ba4c993c.tar.gz
open-iov-af37d9766c5fe4e256e07faefa095535ba4c993c.zip
vgsp: per-channel C597 attachment table, sema_gl_win_drop strip knob, WINPROBE; strip experiment: binds-only windows retire, full draws die in FECS switch-in (SESSION 153 r955-r958)
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c170
-rw-r--r--kernel/gsp_sema_service.c182
2 files changed, 313 insertions, 39 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 5850f00..42a5186 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -19230,7 +19230,7 @@ gsp_phys_gr_m91_fault_cap(const struct gsp_phys_gr_submit *req,
fn = &gsp_phys_fault_notes[(gsp_phys_fault_note_next +
GSP_PHYS_FAULT_NOTE_MAX - 1u) %
GSP_PHYS_FAULT_NOTE_MAX];
- pr_info("vgsp-m91: FAULT-CAP ok=%u faults=%u retry=%s attempts=%u qmd=0x%llx qmd64=%s prog_w48=0x%08x w49=0x%08x prog_va=0x%llx prog_pa=0x%llx code_src=%s off=0x%x code64=%s fault_et=0x%x fault_chid=%u fault_err=\"%.48s\"\n",
+ pr_info("vgsp-m91: FAULT-CAP ok=%u faults=%u retry=%s attempts=%u qmd=0x%llx qmd64=%s prog_w48=0x%08x w49=0x%08x prog_va=0x%llx prog_pa=0x%llx code_src=%s off=0x%x code64=%s fault_et=0x%x fault_chid=%u fault_err=\"%.200s\"\n",
ok ? 1u : 0u, faults,
fast ? "fast-rearm" : (rearmed ? "resched/fresh-entry" : "none"),
attempts, qmd_dst, qhex, qmd[48], qmd[49], pva, ppa, src, off,
@@ -19477,22 +19477,87 @@ static bool gsp_phys_rmcall_gr_3d_reloc(u32 *up_w, u32 *lo_w,
* number of relocated pair(s). Run widths follow the service's decoder:
* op 1/3/5 are 1+count dwords, everything else resyncs one dword.
*/
+/*
+ * SESSION 153-CONTINUED-13 (draw-window strip experiment): comma-separated
+ * hex NVC597 method byte-addresses to REMOVE from a captured 3D window
+ * before the verbatim replay (whole methods - a dropped run takes its
+ * count data words with it). Answers whether a DRAW window's non-retire
+ * lives in the draw content (BEGIN/END/immediate vertices/DRAW_ARRAY) or
+ * in the state binds/method-stream shape. Empty = off (historical
+ * behaviour); live-tunable via sysfs so one boot can sweep the variants.
+ */
+static char *gsp_phys_rmcall_gr_win_drop;
+module_param_named(sema_gl_win_drop, gsp_phys_rmcall_gr_win_drop, charp, 0644);
+MODULE_PARM_DESC(sema_gl_win_drop,
+ "Hex method byte-addresses (comma-separated) to strip from a captured 3D window before replay (draw isolation; default empty)");
+
+static bool gsp_phys_rmcall_gr_win_drop_match(u32 addr)
+{
+ const char *p = gsp_phys_rmcall_gr_win_drop;
+ u32 n = 0;
+
+ if (!p || !*p)
+ return false;
+ while (*p && n < 64) {
+ u32 v = 0;
+ u32 digits = 0;
+
+ while (*p == ' ' || *p == ',' || *p == ':' || *p == ';')
+ p++;
+ for (;;) {
+ char c = *p;
+ u32 d;
+
+ if (c >= '0' && c <= '9')
+ d = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ d = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ d = c - 'A' + 10;
+ else
+ break;
+ if (v <= 0xfffffffu)
+ v = (v << 4) | d;
+ p++;
+ digits++;
+ }
+ if (!digits)
+ break;
+ n++;
+ if (v == addr)
+ return true;
+ }
+ return false;
+}
+
static u32 gsp_phys_rmcall_gr_3d_patch_window(const u32 *in, u32 n, u32 *out,
+ u32 *out_n, u32 *n_dropped,
const struct gsp_phys_gr_submit *req,
u32 *n_shadow)
{
- u32 off = 0, reloc = 0;
+ u32 off = 0, wout = 0, reloc = 0, dropped = 0;
- memcpy(out, in, (size_t)n * 4);
+ *out_n = n;
+ *n_dropped = 0;
while (off < n) {
- u32 hdr = out[off];
+ u32 hdr = in[off];
u32 op = (hdr >> 29) & 0x7u;
u32 cnt = (hdr >> 16) & 0xfffu;
u32 addr = (hdr & 0x1fffu) << 2;
+ u32 span = 1u;
if ((op == 1 || op == 3 || op == 5) && cnt &&
+ off + 1u + cnt <= n)
+ span = 1u + cnt;
+ if (gsp_phys_rmcall_gr_win_drop_match(addr)) {
+ dropped++;
+ off += span;
+ continue;
+ }
+ memcpy(&out[wout], &in[off], (size_t)span * 4);
+ if ((op == 1 || op == 3 || op == 5) && cnt &&
off + 1u + cnt <= n) {
- u32 *d = &out[off + 1];
+ u32 *d = &out[wout + 1];
u32 lo_i = 0;
bool pair = false;
@@ -19533,15 +19598,34 @@ static u32 gsp_phys_rmcall_gr_3d_patch_window(const u32 *in, u32 n, u32 *out,
lo_i = 0;
pair = true;
}
- if (pair && gsp_phys_rmcall_gr_3d_reloc(&d[lo_i],
- &d[lo_i + 1],
- req, n_shadow))
- reloc++;
+ if (pair) {
+ u64 pva = ((u64)(d[lo_i] & 0xffu) << 32) |
+ (u64)(d[lo_i + 1] & 0xfffffffcu);
+ bool ok = gsp_phys_rmcall_gr_3d_reloc(
+ &d[lo_i], &d[lo_i + 1], req,
+ n_shadow);
+ static u32 pair_log;
+
+ if (ok)
+ reloc++;
+ if (pair_log < 48) {
+ pair_log++;
+ pr_info("vgsp-gr: pair addr=0x%x va=0x%llx -> %s0x%llx\n",
+ addr, pva, ok ? "" :
+ "MISS ",
+ ((u64)(d[lo_i] & 0xffu) << 32) |
+ (u64)(d[lo_i + 1] & 0xfffffffcu));
+ }
+ }
+ wout += span;
off += 1u + cnt;
continue;
}
off++; /* header-only / resync, like the service decoder */
+ wout++;
}
+ *out_n = wout;
+ *n_dropped = dropped;
return reloc;
}
@@ -20799,14 +20883,28 @@ gr_page_unmapped:
* held, before the method block is built.
*/
if (stream3d) {
+ u32 win_n = req->stream_n;
+ u32 ndrop = 0;
u32 nrel = gsp_phys_rmcall_gr_3d_patch_window(
- req->stream, req->stream_n, stream_patch, req,
- &n_shadow);
+ req->stream, req->stream_n, stream_patch, &win_n,
+ &ndrop, req, &n_shadow);
win3d = stream_patch;
- win3d_n = req->stream_n;
- pr_info("vgsp-gr: 3D window relocated %u operand pair(s) to shadow VAs (window=%u shadow=%u)\n",
- nrel, win3d_n, n_shadow);
+ win3d_n = win_n;
+ pr_info("vgsp-gr: 3D window relocated %u operand pair(s) to shadow VAs (window=%u shadow=%u dropped=%u)\n",
+ nrel, win3d_n, n_shadow, ndrop);
+ if (ndrop) {
+ static u32 gr3d_drop_log;
+
+ if (gr3d_drop_log < 32) {
+ gr3d_drop_log++;
+ pr_info("vgsp-gr: 3D win-drop h=0x%x push=0x%llx raw=%u kept=%u dropped=%u list=[%s]\n",
+ req->h_object, req->push_va,
+ req->stream_n, win3d_n, ndrop,
+ gsp_phys_rmcall_gr_win_drop ?
+ gsp_phys_rmcall_gr_win_drop : "");
+ }
+ }
/*
* SESSION 153-CONTINUED-11: bounded raw window dump - the
* exact C597 method stream the engine walks (program binds
@@ -21252,6 +21350,50 @@ gr_page_unmapped:
else
w0 = READ_ONCE(*(u32 *)sem_va);
}
+ /*
+ * SESSION 153-CONTINUED-13: early PBDMA fetch probe for a 3D
+ * stream launch - where is the front end while a DRAW window
+ * does not retire? One shot per launch at ~150 ms and ~1.2 s
+ * (5 ms poll), bounded per boot. pbfetch inside the module
+ * pushbuffer page = the walk/exec is stuck in our block;
+ * pbfetch past it = the whole stream was decoded and the
+ * stall is in execution/completion.
+ */
+ if (stream3d && bar0 &&
+ (sked_tick == 30 || sked_tick == 240)) {
+ static u32 winprobe_log;
+ u32 pi;
+
+ if (winprobe_log < 10) {
+ winprobe_log++;
+ pr_info("vgsp-gr: WINPROBE +%ums push=0x%llx words=%u block_dma=0x%llx grfifo=%08x trapped=%08x trapped_lo=%08x\n",
+ sked_tick * GSP_PHYS_RMCALL_POLL_MS,
+ req->push_va, words, sub.pb_dma,
+ ioread32(bar0 + 0x00400504u),
+ ioread32(bar0 + 0x00400704u),
+ ioread32(bar0 + 0x00400708u));
+ for (pi = 0; pi < 12; pi++) {
+ u32 b = 0x40000u + pi * 0x2000u;
+ u32 intr0 = ioread32(bar0 + b + 0x108u);
+ u32 gpf = ioread32(bar0 + b + 0x050u);
+ u32 pbf = ioread32(bar0 + b + 0x054u);
+ u32 pbfhi = ioread32(bar0 + b + 0x058u);
+ u32 hdrsh = ioread32(bar0 + b + 0x118u);
+ u64 fetch64 =
+ ((u64)(pbfhi & 0xffu) << 32) |
+ (u64)(pbf & ~3u);
+
+ if (!intr0 && !gpf && !pbf && !hdrsh)
+ continue;
+ pr_info("vgsp-gr: WINPROBE P%u intr0=%08x gp_put=%u pbfetch=0x%llx hdr=%08x(%s m=0x%x cnt=%u sub=%u)\n",
+ pi, intr0, gpf, fetch64, hdrsh,
+ gsp_phys_pbdma_type_name(hdrsh >> 29),
+ (hdrsh & 0x1fffu) << 2,
+ (hdrsh >> 16) & 0xfffu,
+ (hdrsh >> 13) & 7u);
+ }
+ }
+ }
if (ch_rel_hpa)
w1 = READ_ONCE(*(u32 *)((u8 *)__va(ch_rel_hpa) +
ch_rel_off));
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index ac6f392..6d2bee7 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -7153,6 +7153,104 @@ static u64 svc_gl_att_h; /* channel whose subch carries the C597 bind */
static u32 svc_gl_att_subch;
static u32 svc_gl_draw_log; /* bounded draw-section-open witness */
/*
+ * SESSION 153-CONTINUED-13: the C597 attachment is per-channel. The single
+ * (h_object, subch) slot was overwritten by the RM channel's periodic
+ * C597-bind pushes (h=0xbfef0002, observed every ~7 s on this boot), after
+ * which the GLX client's draw pushes on 0x1000013 failed the BEGIN
+ * recogniser's `svc_gl_att_h == ch->h_object` test and no draw section was
+ * ever opened (a boot-level, order-dependent race: the r954 boot decoded
+ * no such pushes). A small table (first match wins, dedup on note) keeps
+ * every channel's bind sticky independently, so the draw channel's
+ * attachment cannot be stolen.
+ */
+#define SVC_GL_ATT_MAX 8
+static u64 svc_gl_att_tab_h[SVC_GL_ATT_MAX];
+static u8 svc_gl_att_tab_sub[SVC_GL_ATT_MAX];
+
+static void svc_gl_att_note(u64 h, u32 subch)
+{
+ u32 i, free = SVC_GL_ATT_MAX;
+
+ for (i = 0; i < SVC_GL_ATT_MAX; i++) {
+ if (svc_gl_att_tab_h[i] == h &&
+ svc_gl_att_tab_sub[i] == (u8)subch) {
+ /* refresh LRU position: move to slot 0 */
+ if (i) {
+ memmove(&svc_gl_att_tab_h[1],
+ &svc_gl_att_tab_h[0],
+ (size_t)i * sizeof(u64));
+ memmove(&svc_gl_att_tab_sub[1],
+ &svc_gl_att_tab_sub[0],
+ (size_t)i);
+ svc_gl_att_tab_h[0] = h;
+ svc_gl_att_tab_sub[0] = (u8)subch;
+ }
+ return;
+ }
+ if (!svc_gl_att_tab_h[i] && free == SVC_GL_ATT_MAX)
+ free = i;
+ }
+ if (free == SVC_GL_ATT_MAX) {
+ /* table full: evict the oldest (last) slot */
+ free = SVC_GL_ATT_MAX - 1;
+ }
+ memmove(&svc_gl_att_tab_h[1], &svc_gl_att_tab_h[0],
+ (size_t)free * sizeof(u64));
+ memmove(&svc_gl_att_tab_sub[1], &svc_gl_att_tab_sub[0],
+ (size_t)free);
+ svc_gl_att_tab_h[0] = h;
+ svc_gl_att_tab_sub[0] = (u8)subch;
+ /* keep the legacy single slot pointing at the newest note (logging) */
+ svc_gl_att_h = h;
+ svc_gl_att_subch = subch;
+}
+
+static bool svc_gl_att_has(u64 h, u32 subch)
+{
+ u32 i;
+
+ for (i = 0; i < SVC_GL_ATT_MAX; i++)
+ if (svc_gl_att_tab_h[i] == h &&
+ svc_gl_att_tab_sub[i] == (u8)subch)
+ return true;
+ return false;
+}
+
+static u32 svc_gl_att_subch_of(u64 h)
+{
+ u32 i;
+
+ for (i = 0; i < SVC_GL_ATT_MAX; i++)
+ if (svc_gl_att_tab_h[i] == h)
+ return svc_gl_att_tab_sub[i];
+ return 0xffu;
+}
+
+static void svc_gl_att_clear(u64 h, u32 subch)
+{
+ u32 i;
+
+ for (i = 0; i < SVC_GL_ATT_MAX; i++)
+ if (svc_gl_att_tab_h[i] == h &&
+ svc_gl_att_tab_sub[i] == (u8)subch) {
+ u32 n = SVC_GL_ATT_MAX - 1 - i;
+
+ if (n)
+ memmove(&svc_gl_att_tab_h[i],
+ &svc_gl_att_tab_h[i + 1],
+ (size_t)n * sizeof(u64));
+ if (n)
+ memmove(&svc_gl_att_tab_sub[i],
+ &svc_gl_att_tab_sub[i + 1],
+ (size_t)n);
+ svc_gl_att_tab_h[SVC_GL_ATT_MAX - 1] = 0;
+ svc_gl_att_tab_sub[SVC_GL_ATT_MAX - 1] = 0;
+ if (svc_gl_att_h == h)
+ svc_gl_att_h = svc_gl_att_tab_h[0];
+ return;
+ }
+}
+/*
* SESSION 153 (G-B gate: the client's own C597 draws must open sections).
* The replay guard at svc_gl_flush consults svc_gr_cand_push_seen(), which
* returns true when the push VA sits in the GR candidate ring - even when
@@ -7411,7 +7509,13 @@ static void svc_gl_hold_store(u32 h, u64 prog, u64 param, u32 psize,
{
u32 i, free = SVC_GL_HOLD_MAX;
- if (!h || !prog || !param || !rel)
+ /*
+ * SESSION 153-CONTINUED-13: rel == 0 is admitted (a section that has
+ * real operands but flushed before the channel's release was decoded
+ * stashes them here); a later call with rel != 0 completes the entry
+ * and a rel == 0 call must NEVER wipe a stored release.
+ */
+ if (!h || !prog || !param)
return;
for (i = 0; i < SVC_GL_HOLD_MAX; i++) {
if (svc_gl_hold_tab[i].h == h) {
@@ -7427,8 +7531,10 @@ static void svc_gl_hold_store(u32 h, u64 prog, u64 param, u32 psize,
svc_gl_hold_tab[free].prog_va = prog;
svc_gl_hold_tab[free].param_va = param;
svc_gl_hold_tab[free].param_size = psize;
- svc_gl_hold_tab[free].rel_va = rel;
- svc_gl_hold_tab[free].rel_payload = rpay;
+ if (rel) {
+ svc_gl_hold_tab[free].rel_va = rel;
+ svc_gl_hold_tab[free].rel_payload = rpay;
+ }
}
static bool svc_gl_hold_load(u32 h, u64 *prog, u64 *param, u32 *psize,
@@ -7770,7 +7876,30 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu,
}
if (!svc_gl.prog_va || !svc_gl.param_va ||
!svc_gl.rel_va) {
- if (gsp_sema_dbg && svc_gl_skip_log < 16) {
+ /*
+ * SESSION 153-CONTINUED-13: the release may be
+ * decoded AFTER this section in ring order
+ * (the r955 init: the 24 B release pushes sit
+ * behind the 1524 B init push in the ring, so
+ * every replay pass of the section flushed
+ * before svc_gl.rel_va was known). When the
+ * operands are real but only the release is
+ * missing, stash them for the channel so the
+ * next section/pass (by then the constant
+ * release stream has been decoded) captures
+ * with src=hold instead of losing the init
+ * capture - without which the guest's GLX
+ * init completion degrades and the client
+ * never emits its draw pushes at all.
+ */
+ if (svc_gl.prog_va && svc_gl.param_va &&
+ !svc_gl.rel_va)
+ svc_gl_hold_store(ch->h_object,
+ svc_gl.prog_va,
+ svc_gl.param_va,
+ svc_gl.param_size,
+ 0, 0);
+ if (gsp_sema_dbg && svc_gl_skip_log < 2048) {
svc_gl_skip_log++;
pr_info("sema-gl: flush skip h=0x%x push=0x%llx prog=0x%llx param=0x%llx rel=0x%llx (no operands, no hold)\n",
ch->h_object, push_va,
@@ -12705,7 +12834,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
* colour target, constant-buffer selectors).
*/
if (gsp_sema_gl_xlate && !ch->engine_type && trusted &&
- !svc_gl_att_h) {
+ !svc_gl_att_has(ch->h_object, 0)) {
u32 o2 = 0;
while (o2 + 4 <= len) {
@@ -12717,8 +12846,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
sc2 = (h2 >> 13) & 0x7;
ad2 = (h2 & 0x1fff) << 2;
if (op2 == 4 && ad2 == 0x1618 && sc2 == 0) {
- svc_gl_att_h = ch->h_object;
- svc_gl_att_subch = 0;
+ svc_gl_att_note(ch->h_object, 0);
if (gsp_sema_dbg && svc_gl_draw_log < 64) {
svc_gl_draw_log++;
pr_info("sema-gl: attach-on-BEGIN h=0x%x push=0x%llx off=0x%x (no explicit C597 bind seen)\n",
@@ -12760,13 +12888,17 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
* the replay channel cannot translate (the r929 v1 fault
* class), so they must stay outside the sliced window.
*/
- if (gsp_sema_gl_xlate && !ch->engine_type &&
- svc_gl_att_h == ch->h_object) {
- if (subch != svc_gl_att_subch)
- gl_win_start = 0;
- else if (!gl_win_start &&
- !(op == 1 && addr >= 0x1b00 && addr <= 0x1b0c))
- gl_win_start = off;
+ if (gsp_sema_gl_xlate && !ch->engine_type) {
+ u32 as = svc_gl_att_subch_of(ch->h_object);
+
+ if (as != 0xffu) {
+ if (subch != as)
+ gl_win_start = 0;
+ else if (!gl_win_start &&
+ !(op == 1 && addr >= 0x1b00 &&
+ addr <= 0x1b0c))
+ gl_win_start = off;
+ }
}
/*
@@ -13028,8 +13160,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
*/
if (gsp_sema_gl_xlate && !ch->engine_type && op == 4 &&
addr == 0x1618 && !svc_gl.seen &&
- svc_gl_att_h == ch->h_object &&
- subch == svc_gl_att_subch) {
+ svc_gl_att_has(ch->h_object, subch)) {
u64 keep_rel = svc_gl.rel_va;
u32 keep_pay = svc_gl.rel_payload;
u32 wstart = gl_win_start ? gl_win_start : off;
@@ -13061,8 +13192,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
if (gsp_sema_gl_xlate && op == 4 && addr >= 0x2000 &&
addr < 0x2800 && (addr & 0x3f) == 0 &&
((svc_gl.seen && subch == svc_gl.subch) ||
- (svc_gl_att_h == ch->h_object &&
- subch == svc_gl_att_subch))) {
+ svc_gl_att_has(ch->h_object, subch))) {
u32 j = (addr - 0x2000) / 0x40;
if (j < 32)
@@ -13170,9 +13300,11 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
* remember it so the class-space recognizer
* (BEGIN 0x1618, below) accepts this channel's
* later per-push-CONTENT pushes that carry no
- * SET_OBJECT of their own. */
- svc_gl_att_h = ch->h_object;
- svc_gl_att_subch = subch;
+ * SET_OBJECT of their own.
+ * SESSION 153-CONTINUED-13: per-channel table -
+ * a foreign channel's periodic C597 bind must
+ * not steal this channel's attachment. */
+ svc_gl_att_note(ch->h_object, subch);
/*
* SESSION 153: witness every C597 section open
* (bounded) - it is the recognizer-side proof
@@ -13194,10 +13326,10 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
/* A different class bound over the attached
* subchannel replaces the C597 bind: drop the
* attachment so the class-space recognizer
- * cannot misread methods of the new class. */
- if (ch->h_object == svc_gl_att_h &&
- subch == svc_gl_att_subch)
- svc_gl_att_h = 0;
+ * cannot misread methods of the new class.
+ * SESSION 153-CONTINUED-13: clears only this
+ * channel's entry. */
+ svc_gl_att_clear(ch->h_object, subch);
}
} else if (gsp_sema_gl_xlate && svc_gl.seen &&
subch == svc_gl.subch) {