diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-29 08:30:32 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-29 08:30:32 -0400 |
| commit | af37d9766c5fe4e256e07faefa095535ba4c993c (patch) | |
| tree | 277840997d0cb79fad1e3ec0d94a3e38af2a57fb /kernel | |
| parent | 94a0f3de36a113b350ec9a86e11909c1684acdc4 (diff) | |
| download | open-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.c | 170 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.c | 182 |
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) { |
