summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-19 17:35:21 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-19 19:23:06 -0400
commite20123d000807b1dd0c728870961e31b1f0bffb9 (patch)
tree07a89a5c71b3c6db1acbffa6566315a68d95af7c /kernel/gsp_sema_service.c
parent48a367e98ddd057155745699b74ed57c8c0c5612 (diff)
downloadopen-iov-e20123d000807b1dd0c728870961e31b1f0bffb9.tar.gz
open-iov-e20123d000807b1dd0c728870961e31b1f0bffb9.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).
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c81
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)) {