diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-19 17:35:21 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-19 19:23:21 -0400 |
| commit | 4e863b8ed36c5b7bbf64520491f5f1b9d2929684 (patch) | |
| tree | 07a89a5c71b3c6db1acbffa6566315a68d95af7c | |
| parent | c386b62988fa36fed024f0ec6112a0d6c9a475b6 (diff) | |
| download | open-iov-4e863b8ed36c5b7bbf64520491f5f1b9d2929684.tar.gz open-iov-4e863b8ed36c5b7bbf64520491f5f1b9d2929684.zip | |
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).
| -rw-r--r-- | kernel/gsp_sema_service.c | 81 |
1 files 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, @@ -8451,6 +8459,35 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, 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 * copy engine advances the other by the transfer @@ -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)) { |
