From 9d9f2eb5947d90db7430a4bdbe65766af77a99c3 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 19 Oct 2026 17:13:31 -0400 Subject: vgsp: fail4 - definitive rec-content witness (data[0..2] first8 at the rec hpa) r295 measurement: rec[0] va=0x72a93cc00000 hpa=0x119155000 first8=43100000 43108000 = floats 144.0 144.5 = a[524288..524289] - i.e. the first A-rec's backing page already holds the +2 MB data, before copy-in. Chained with the r285 upload witnesses (the H2D op sources read the other buffer's chunk-2/3 data), the +2 MB phase originates on the HOST-BUFFER side of the uploads (the pinned/staged source resolution for the client's host buffers), not in the GMMU walk (verified correct against the driver's own format: PD3[48:47]/PD2[46:38]/ PD1[37:29]/PD0[28:21]/PT[20:12]). --- kernel/gsp_phys_booter.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 101397f..3fee456 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -19610,10 +19610,28 @@ gr_page_unmapped: req->data[0].va, (u64)req->n_data << 12, (u64)dcopied << 12); - for (di = 0; di < req->n_data && di < 3; di++) - pr_info("vgsp-gr: data[%u] va=0x%llx hpa=0x%llx reloc=0x%llx\n", + for (di = 0; di < req->n_data && di < 3; di++) { + u32 w0 = 0, w1 = 0; + + /* + * fail4 definitive witness: the bytes the engine will + * read for the first recs (the rec hpa's content) + * beside the rec identity - names a +2 MB rec-page + * phase directly (client a[0..3] = 00000000 + * 0000003f 0000003f... would appear as exp[2M] + * values if the hpa points 512 pages late). + */ + if (req->data[di].hpa) { + const u32 *p = (const u32 *)__va( + req->data[di].hpa); + + w0 = p[0]; + w1 = p[1]; + } + pr_info("vgsp-gr: data[%u] va=0x%llx hpa=0x%llx reloc=0x%llx first8=%08x %08x\n", di, req->data[di].va, req->data[di].hpa, - req->data[di].reloc_va); + req->data[di].reloc_va, w0, w1); + } } /* -- cgit v1.2.3 From 48a367e98ddd057155745699b74ed57c8c0c5612 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 19 Oct 2026 17:17:18 -0400 Subject: vgsp: fail4 - pipeline-order source snapshot for held staged copies The m169 device-dst guard defers a staged H2D up to 3 s; the driver's ping-pong staging buffers are overwritten meanwhile, so a deferred read returned a later chunk's content (the +2 MB vector_add phase = the 2x1 MB staging stride). Held copies now snapshot their source at hold time (bounded: 8 slots x 4 MB, 30 s TTL) and the retried execution copies from the snapshot, matching the hardware's in-order staging read. r296 A/B: the snapshot never fires for vector_add - its H2D dsts resolve with pins promptly and execute without the hold; the +2 MB persists identically. So the staging overrun happens WITHOUT the guard: the driver's 2-buffer staging discipline relies on the copy's completion fence (a semaphore applied when the copy executes) to pace the restaging; if our completion for chunk i arrives before/independent of the staging read, the driver restages and our later decode reads chunk i+2. Next lead: the staging fence's increment timing vs the copy's execution (the release-before-work class extended to the H2D staging fences), not the m169 hold. --- kernel/gsp_sema_service.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 6c75a9e..ce15524 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -5235,6 +5235,105 @@ static void svc_copy_audit_chunk(struct nv_vgpu_device *vgpu, u64 dst_va, return (rc_); \ } while (0) +/* + * fail4: pipeline-order source snapshot for held copies. The m169 + * device-dst guard defers a staged H2D (host->device) for up to 3 s; + * the driver's ping-pong staging buffers are overwritten by the next + * chunk meanwhile, so the deferred read returns the content of a later + * chunk (vector_add: device a[i] pages held a[i+2 MB] - exactly the + * 2x1 MB staging stride). A held copy snapshots its source at hold + * time and the retried execution copies from the snapshot, matching + * the hardware's in-order read of the staging. + */ +#define SVC_COPY_SNAP_N 8 +#define SVC_COPY_SNAP_MAX (4u << 20) +#define SVC_COPY_SNAP_TTL_MS 30000u +struct svc_copy_snap { + u64 dst, src; + size_t total; + u8 *buf; + unsigned long stamp; +}; +static struct svc_copy_snap svc_copy_snaps[SVC_COPY_SNAP_N]; + +static u8 *svc_copy_snap_lookup(u64 dst, u64 src, size_t total) +{ + u32 i; + + for (i = 0; i < SVC_COPY_SNAP_N; i++) + if (svc_copy_snaps[i].buf && + svc_copy_snaps[i].dst == dst && + svc_copy_snaps[i].src == src && + svc_copy_snaps[i].total == total) + return svc_copy_snaps[i].buf; + return NULL; +} + +static void svc_copy_snap_free(u64 dst, u64 src, size_t total) +{ + u32 i; + + for (i = 0; i < SVC_COPY_SNAP_N; i++) + if (svc_copy_snaps[i].buf && + svc_copy_snaps[i].dst == dst && + svc_copy_snaps[i].src == src && + svc_copy_snaps[i].total == total) { + kfree(svc_copy_snaps[i].buf); + svc_copy_snaps[i].buf = NULL; + return; + } +} + +/* Capture the source of a virtual-operand copy about to be held. */ +static void svc_copy_snap_capture(struct nv_vgpu_device *vgpu, u64 dst, + u64 src, size_t total) +{ + struct svc_copy_snap *s = NULL; + u8 *buf; + size_t o; + u32 i; + + if (!total || total > SVC_COPY_SNAP_MAX) + return; + if (svc_copy_snap_lookup(dst, src, total)) + return; /* already captured */ + for (i = 0; i < SVC_COPY_SNAP_N; i++) { + if (!svc_copy_snaps[i].buf) { + s = &svc_copy_snaps[i]; + break; + } + if (time_after(jiffies, svc_copy_snaps[i].stamp + + msecs_to_jiffies(SVC_COPY_SNAP_TTL_MS))) { + kfree(svc_copy_snaps[i].buf); + svc_copy_snaps[i].buf = NULL; + s = &svc_copy_snaps[i]; + break; + } + } + if (!s) + return; /* all slots live: keep the historical behaviour */ + buf = kmalloc(total, GFP_KERNEL); + if (!buf) + return; + for (o = 0; o < total; ) { + size_t chunk = min_t(size_t, 0x1000 - ((src + o) & 0xfff), + total - o); + + if (svc_read(vgpu, src + o, buf + o, chunk)) { + kfree(buf); + return; + } + o += chunk; + } + s->dst = dst; + s->src = src; + s->total = total; + s->stamp = jiffies; + s->buf = buf; + pr_info_ratelimited("vgsp-sema: copy snapshot captured dst=0x%llx src=0x%llx total=%zu (held staged copy)\n", + dst, src, total); +} + static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, u32 dst_phys, u32 dst_aperture, u32 src_phys, u32 src_aperture, u64 *done_out) @@ -5248,6 +5347,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, u32 dst_prov = 0, src_prov = 0; bool bigcopy_this = false; bool audit = total >= SVC_COPY_AUDIT_MIN; + u8 *snap = NULL; static u64 bigcopy_log; bool trace64 = (total == 65536u); const char *dir = "?"; @@ -5267,6 +5367,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, svc.cur_ch, dst, src, total, dst_phys, dst_aperture, src_phys, src_aperture); } + snap = svc_copy_snap_lookup(dst_orig, src_orig, total); if (!dst_phys) { u64 pa; @@ -5338,6 +5439,13 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, if (svc.copy_dst_hold <= 16) pr_info("sema-svc: device-dst copy held: dst=0x%llx prov=%u (no pin yet; stale-table guard)\n", dst_orig, dst_prov); + /* + * fail4: the staging source is valid NOW; snapshot it so + * the deferred execution copies the pipeline-order bytes. + */ + if (!src_phys && src_orig >= SVC_VAS_FLOOR) + svc_copy_snap_capture(vgpu, dst_orig, src_orig, + total); return -ENOENT; } /* @@ -5930,6 +6038,8 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, for (po = 0; po < total; po += SEMA_PAGE_SIZE) svc_ledger_store(dst_orig + po, dst + po, cap); } + if (snap) + svc_copy_snap_free(dst_orig, src_orig, total); if (done_out) *done_out = (u64)o; /* o == total on the success path */ return 0; -- cgit v1.2.3 From e20123d000807b1dd0c728870961e31b1f0bffb9 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 19 Oct 2026 17:35:21 -0400 Subject: vgsp: fail4 r297-r300 - decode-time staging snapshot (H2D shapes only) + ops-order release guard 1. CONT.53 step (1): device-dst copies from host sources now snapshot the source at op-build (bounded pool 16 x 4 MB, 30 s TTL) and execute from the snapshot, so the staging read happens at the push's processing position. 2. The capture gate is aperture-based (dst VID, src SYS) after the r300 captures showed a naive VA-floor gate also caught D2H readbacks and froze pre-kernel zeros. 3. Ops-order release guard: a pass that built ops queues its releases through the pending pass instead of applying inline, so a fence never clears before the pass's copy ops read their source. A/B (r297/r299/r300): snapshots fire (6-7 per run) but the +2 MB phase persists (win@0/1M = exp[+2M]); the r300 capture contents show the H2D op sources already carry late-chunk data at decode - the scrambling is at the driver's staging hand-off into the push stream, before our service sees the op (next instrument: correlate the client's PTRS with per-capture buffer identity). --- kernel/gsp_sema_service.c | 81 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index ce15524..b884bb5 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -5245,7 +5245,7 @@ static void svc_copy_audit_chunk(struct nv_vgpu_device *vgpu, u64 dst_va, * time and the retried execution copies from the snapshot, matching * the hardware's in-order read of the staging. */ -#define SVC_COPY_SNAP_N 8 +#define SVC_COPY_SNAP_N 16 #define SVC_COPY_SNAP_MAX (4u << 20) #define SVC_COPY_SNAP_TTL_MS 30000u struct svc_copy_snap { @@ -5318,8 +5318,12 @@ static void svc_copy_snap_capture(struct nv_vgpu_device *vgpu, u64 dst, for (o = 0; o < total; ) { size_t chunk = min_t(size_t, 0x1000 - ((src + o) & 0xfff), total - o); + u64 pa = 0; + u32 ap = 0; - if (svc_read(vgpu, src + o, buf + o, chunk)) { + /* The source is a virtual host VA; resolve per page first. */ + if (svc_op_translate(vgpu, src + o, &pa, &ap) || + svc_read(vgpu, pa, buf + o, chunk)) { kfree(buf); return; } @@ -5330,8 +5334,12 @@ static void svc_copy_snap_capture(struct nv_vgpu_device *vgpu, u64 dst, s->total = total; s->stamp = jiffies; s->buf = buf; - pr_info_ratelimited("vgsp-sema: copy snapshot captured dst=0x%llx src=0x%llx total=%zu (held staged copy)\n", - dst, src, total); + pr_info_ratelimited("vgsp-sema: copy snapshot captured dst=0x%llx src=0x%llx total=%zu first4=%08x %08x %08x %08x\n", + dst, src, total, + total >= 4 ? *(const u32 *)buf : 0, + total >= 8 ? *(const u32 *)(buf + 4) : 0, + total >= 12 ? *(const u32 *)(buf + 8) : 0, + total >= 16 ? *(const u32 *)(buf + 12) : 0); } static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, @@ -8450,6 +8458,35 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, if (n_ops != n_ops_before) { struct svc_memset_op *lm = &ops[n_ops - 1]; + /* + * fail4 CONT.53: H2D-shaped copies (virtual + * device destination, virtual host source) + * read the driver's ping-pong staging. The + * driver paces restaging on the copy's + * completion fence; our execution may run + * later than the push's processing position, + * so capture the source NOW (bounded pool) + * and let svc_copy execute from the capture - + * the hardware's in-order staging read. + */ + /* + * H2D shape ONLY: device destination (VID + * aperture), host source (SYS). A D2H readback + * (host dst) captured here would freeze + * pre-kernel zeros (observed in the r300 + * captures) and break readbacks. + */ + if (lm->type == 1 && !lm->phys && + lm->dst >= SVC_VAS_FLOOR && + lm->aperture == CE_APERTURE_VID && + !lm->src_phys && + lm->src >= SVC_VAS_FLOOR && + lm->src_aperture == CE_APERTURE_SYS && + lm->bytes <= SVC_COPY_SNAP_MAX) + svc_copy_snap_capture(vgpu, lm->dst, + lm->src, + lm->bytes); + /* * fail4 CE linear auto-advance, BOTH sides: the * driver re-sets only ONE offset per op and the @@ -8815,7 +8852,26 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, */ svc.fwd_rel_overflow++; svc_fwd_soft_copy_inline(vgpu); - if (svc_rel_apply_launch(vgpu, ch, + /* + * fail4 CONT.53: never clear a + * push's fence before its ops + * read their source. The pass's + * ops run at the pass end; the + * driver's ping-pong staging + * restages as soon as the fence + * clears, and a later op read + * then returns chunk+N bytes + * (vector_add +2 MB). Queue the + * release through the pending + * pass instead. + */ + if (n_ops > 0) { + svc_pending_add(sem_va, + st.sem_payload, + inc ? 1u : 0u); + svc_rel_va_seen = sem_va; + svc_rel_count++; + } else if (svc_rel_apply_launch(vgpu, ch, sem_va, st.sem_payload, cur, pending, @@ -8849,7 +8905,20 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, svc_fwd_rel_direct_note(ch->h_object, sem_va, st.sem_payload); - if (svc_rel_apply_launch(vgpu, ch, sem_va, + /* + * fail4 CONT.53: same ops-order + * guard as above - a pass with + * pending copy ops must run + * them before its fence clears. + */ + if (n_ops > 0) { + svc_pending_add(sem_va, + st.sem_payload, + inc ? 1u : 0u); + svc_rel_va_seen = sem_va; + svc_rel_count++; + } else if (svc_rel_apply_launch(vgpu, ch, + sem_va, st.sem_payload, cur, pending, inc, inc_apply)) { -- cgit v1.2.3 From 9218a1c5e420a834276e0c179b7d89a149b6533c Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 19 Oct 2026 18:28:36 -0400 Subject: vgsp: fail4 - denied device-dst copies hold+retry (fix the chunk drop) Root cause of the vector_add chunk drop (CONT.55 chase): the sw-copy client's GR-classified GRCE channel (eng=0, h=0x5c000059) decodes its 1MB H2D chunk copies as CE transfers, but ops on that channel run only once the pin/trust stream (injected) reaches each push page. The first pass over a chunk push lands before that; with allow_ops=0 the copy was never built and the entry was consumed silently. All later passes classify as replays (slot_ops_complete=1), so the entry was never retried: 6 of 8 chunks skipped, kernel computed on stale VRAM (vector_add r302-r307: 2-5 of 8 chunk ops ever existed, the rest never ran; the +2MB 'phase' signature is stale residue). Fix: a denied launch that WOULD have built a type=1 device-dst copy (no remap, both offsets, out >= SVC_VAS_FLOOR) with a trusted push now marks the pass op-pending. op_tr_pending un-completes the slot, so the next pass is treated fresh and the copy runs as soon as trust (injected with allow=1) or the operand translation arrives - the existing m163/opdef hold+retry machinery. Replay passes are deliberately eligible (that is what makes the retry possible); a per-slot slot_pend_tries cap (4 per put epoch) prevents a slot whose trust never arrives from wedging the channel in 10s hold cycles. Measured (r308, sema_dbg): all 8 consecutive chunk dsts build ops (0x...cc..d3) and retry to success - 28 CEAUDIT rc=0 soft copies, 38 rc=0 vs 20 rc=-2 executions; previously max 5 dsts and only the last 2-3 ran. Regression checks on r309 with the fix: probe RAWA2+PROBE2B bad=0, victory_mail OK, victory_matmul OK (one transient first-run fail, clean re-run), transformer OK. vector_add now advances through the full H2D set but still does not complete (retry storms stretch the copy phase; the run later wedges in the GR stale-wedge recovery loop - named as the next lead). Diagnostics kept (dbg-gated, bounded): sema-pend set/hold witness, sema-consume consumed-slot witness, sema-entry de-gated for eng=0 channels, dmatrace extended with replay/eng/pend_would, budgets raised under sema_dbg so boot init cannot spend the trace before the run. --- kernel/gsp_sema_service.c | 115 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index b884bb5..4259314 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -260,6 +260,8 @@ struct svc_channel { * window (observed: one 8 s grace per push, * serializing the runtime init) */ DECLARE_BITMAP(slot_done_epoch, SVC_GPFIFO_MAX_BITS); + u8 slot_pend_tries[SVC_GPFIFO_MAX_BITS]; /* fail4 r308: bounded + * re-holds of a denied device-dst copy slot */ /* GPFIFO slots already consumed in the current * put epoch (the client's put value since it * last wrapped). A pin-batch rewind replays @@ -821,6 +823,7 @@ struct sema_svc { * trace (every push, bounded) */ u64 opadd_log; /* fail4: every op appended */ u64 dmatrace_log; /* fail4: denied-transfer trace */ + u64 pend_dbg_log; /* fail4 r305: pending/hold witness */ u64 copyent_log; /* fail4: svc_copy entry trace */ u64 bigrun_log; /* fail4: big method-data run headers */ u64 lid_hdr_log; /* fail4: LOAD_INLINE_DATA headers */ @@ -6359,7 +6362,7 @@ static void svc_run_ops(struct nv_vgpu_device *vgpu, struct svc_memset_op *ops, * read-back signature: always keep room for it past the * general trace budget so the DtoH's src/dst/rc is on record. */ - if ((svc.op_trace_log < 2048 && + if ((svc.op_trace_log < (gsp_sema_dbg ? 32768 : 2048) && (time_before(jiffies, svc.op_trace_until) || m->dst >= SVC_VAS_FLOOR || (m->type == 1 && !m->src_phys && m->src >= SVC_VAS_FLOOR))) || @@ -7579,7 +7582,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, svc_fwd_defer_armed = false; svc.pages_decoded++; /* Diagnostic: name every push decoded in the post-completion window. */ - if (svc.op_trace_log < 2048 && + if (svc.op_trace_log < (gsp_sema_dbg ? 32768 : 2048) && time_before(jiffies, svc.op_trace_until)) { svc.op_trace_log++; pr_info("sema-pushtrace: h=0x%x eng=%u va=0x%llx len=%u allow=%d trusted=%d\n", @@ -7592,7 +7595,13 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, * above can miss a whole client's push stream (unidentified channel, * no bridge completion to arm the window); this record cannot. */ - if (svc.pushtrace_all < 512) { + /* + * fail4 r302: with sema_dbg on the boot-time driver init spends the + * 512-line budget long before the run under diagnosis, leaving the + * interesting push stream (a later client's copies) invisible. The + * debug flag raises the bound so one boot covers init + run. + */ + if (svc.pushtrace_all < (gsp_sema_dbg ? 32768 : 512)) { svc.pushtrace_all++; pr_info("sema-pushall: h=0x%x eng=%u va=0x%llx pa=0x%llx len=%u allow=%d trusted=%d first8=%08x %08x\n", ch->h_object, ch->engine_type, push_va, page_pa, len, @@ -8333,7 +8342,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, } /* Diagnostic: full operand state in the post-completion * window (or for high device VAs), bounded. */ - if (svc.op_trace_log < 2048 && ch->h_object && + if (svc.op_trace_log < (gsp_sema_dbg ? 32768 : 2048) && ch->h_object && (time_before(jiffies, svc.op_trace_until) || st.offset_out >= SVC_VAS_FLOOR || st.offset_in >= SVC_VAS_FLOOR)) { @@ -8441,13 +8450,79 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, * wholesale in that case, so this class was invisible. */ if (gsp_sema_dbg && transfer != 0 && !allow_ops && - svc.dmatrace_log < 64) { + svc.dmatrace_log < (gsp_sema_dbg ? 4096 : 64)) { svc.dmatrace_log++; - pr_info("sema-dmatrace: denied h=0x%x push=0x%llx dma=0x%08x line=%u in=0x%llx out=0x%llx have_in=%u have_out=%u have_remap=%u trusted=%d\n", + pr_info("sema-dmatrace: denied h=0x%x push=0x%llx dma=0x%08x line=%u in=0x%llx out=0x%llx have_in=%u have_out=%u have_remap=%u trusted=%d replay=%d eng=%u pend_would=%d\n", ch->h_object, push_va, dma, st.line_length, st.offset_in, st.offset_out, st.have_in, st.have_out, - st.have_remap, trusted); + st.have_remap, trusted, replay, + ch->engine_type, + (!allow_ops && trusted && + !ch->engine_type && transfer != 0 && + st.line_length && st.have_out && + st.have_in && + !DMA_REMAP_ENABLE(dma) && + st.offset_out >= SVC_VAS_FLOOR && + entry_idx != SVC_ENTRY_NONE && + entry_idx < SVC_GPFIFO_MAX_BITS && + ch->slot_pend_tries[entry_idx] < 4) ? 1 : 0); + } + /* + * fail4 r302: a denied device-destination copy that + * WOULD have built a type=1 op (the exact branch shape + * above: no remap, both offsets, device dst) must not + * be consumed silently. This is the sw-copy client + * mode: the GR-classified GRCE channel's ops run only + * once the pin/trust stream (injected) reaches the + * entry, and the first pass over a chunk push lands + * before that - the copy then never ran and the guest + * computed on stale VRAM (vector_add r302: chunk + * copies cc..d1 skipped; only the tail entries were + * re-decoded by a rewind and ran). Mark the pass + * op-pending so the pump holds the entry through the + * m163/opdef machinery and the retry runs the copy as + * soon as the trust (or the operand translation) + * arrives; the bounded SVC_OPDEF_HOLD_MS expiry keeps + * the pre-existing skip as the last resort. + */ + if (!allow_ops && trusted && + !ch->engine_type && transfer != 0 && + st.line_length && st.have_out && st.have_in && + !DMA_REMAP_ENABLE(dma) && + st.offset_out >= SVC_VAS_FLOOR) { + /* + * r308: the `!replay` gate above kept this + * dead on the sw-copy channel: after the first + * consumed pass every later pass classifies as + * a replay, so the denied chunk copies were + * never retried (vector_add: 6 of 8 chunks + * skipped). A replay pass that marks the slot + * pending un-completes it (slot_ops_complete + * is written from svc.op_tr_pending below), so + * the next pass is treated fresh and the copy + * runs once trust/translation arrives. The + * per-slot counter caps the re-holds so a slot + * whose trust never arrives cannot wedge the + * channel in 10 s hold cycles. + */ + if (entry_idx != SVC_ENTRY_NONE && + entry_idx < SVC_GPFIFO_MAX_BITS && + ch->slot_pend_tries[entry_idx] < 4) { + ch->slot_pend_tries[entry_idx]++; + svc.op_tr_pending = 1; + if (gsp_sema_dbg && + svc.pend_dbg_log < 512) { + svc.pend_dbg_log++; + pr_info("sema-pend: h=0x%x push=0x%llx idx=%u out=0x%llx in=0x%llx line=%u replay=%d trusted=%d tries=%u -> op_tr_pending\n", + ch->h_object, push_va, + entry_idx, st.offset_out, + st.offset_in, + st.line_length, + replay, trusted, + ch->slot_pend_tries[entry_idx]); + } + } } /* * fail4: name every op appended to this pass (copy or @@ -8938,7 +9013,8 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, off += 4 + count * 4; } - if (gsp_sema_dbg && ch->h_object && svc.entry_log < 512) { + if (gsp_sema_dbg && ch->h_object && + svc.entry_log < 16384) { svc.entry_log++; { u8 tail[24]; @@ -12993,6 +13069,20 @@ static bool svc_entry_want_reached(struct nv_vgpu_device *vgpu, /* Mark a consumed GPFIFO slot for the current put epoch. */ static void svc_replay_note(struct svc_channel *ch, u32 idx, u32 put) { + static u32 consume_log; + + /* + * fail4 r303: name every consumed slot (all channels). Paired with + * the sema-entry decode rows this shows exactly which entries were + * consumed without ops and when (the vector_add chunk-drop chase: + * a consumed slot whose decode row carried a device-dst copy but + * whose op never ran is the silent skip under diagnosis). + */ + if (gsp_sema_dbg && consume_log < 16384) { + consume_log++; + pr_info("sema-consume: h=0x%x idx=%u put=%u\n", + ch->h_object, idx, put); + } (void)put; /* * STALL FIX (entry=82/pay=84 class, r186): the entry leaving the @@ -17082,7 +17172,7 @@ static bool svc_push_read_displaced(struct nv_vgpu_device *vgpu, u32 h, static void svc_entry_outcome(const char *what, const struct svc_channel *ch, u64 idx, u64 va, u32 len) { - if (!gsp_sema_dbg || !ch->engine_type || svc.gpfifo_entry_log >= 512) + if (!gsp_sema_dbg || svc.gpfifo_entry_log >= 16384) return; svc.gpfifo_entry_log++; pr_info("sema-entry: %s h=0x%x idx=%llu va=0x%llx len=%u want=%u exp=%u unread=%d\n", @@ -17781,6 +17871,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) } } bitmap_zero(ch->slot_done_epoch, SVC_GPFIFO_MAX_BITS); + memset(ch->slot_pend_tries, 0, + sizeof(ch->slot_pend_tries)); /* GRFIX FIX1b: a recycled slot in the next put epoch * gets a fresh absolute-bound record; without this a * wrapped slot would inherit a stale expired launch @@ -18410,6 +18502,11 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) svc_opdef_hold(vgpu, ch, (u32)idx)) { svc.gpfifo_nomap++; + if (gsp_sema_dbg && svc.pend_dbg_log < 1024) { + svc.pend_dbg_log++; + pr_info("sema-pend: hold h=0x%x idx=%u va=0x%llx\n", + ch->h_object, (u32)idx, va); + } /* * P6b wave 1.5: * releases recorded -- cgit v1.2.3