summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-23 10:29:47 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-23 10:29:47 -0400
commite1b07df46b10f64dfcf93e53ee966c905d3e6e16 (patch)
treeb18afc81efd6c83db8b6bee9f749e6e2540bfe5c /kernel/gsp_sema_service.c
parent8c30b1108dc5b368ccd5611076c0aa7dafecd892 (diff)
downloadopen-iov-e1b07df46b10f64dfcf93e53ee966c905d3e6e16.tar.gz
open-iov-e1b07df46b10f64dfcf93e53ee966c905d3e6e16.zip
vgsp-sema r540: a denied transfer op keeps its slot incomplete past the pend cap
The r539 boot showed the 5-minute device-init stall class live: a GRCE channel push (eng=0) carrying an H2D copy is decoded before the pin stream reaches its operands, so allow_ops=0 and the copy is denied; the r308 path sets op_tr_pending and holds the entry. That path is capped at 4 tries per slot ('so a slot whose trust never arrives cannot wedge the channel'), but once the cap is hit op_tr_pending stays 0 and svc_decode_stream's tail marks the slot COMPLETE - so every later pass classifies the entry as a replay and suppresses the copy forever. The pin arrives seconds later; the copy still never runs and the client spins at DEVICE until UVM's own retry. Evidence (r539, /tmp/opencode/r539-live.log): held idx 89/91..94 on h=0x5c000059 with 'denied ... replay=1 trusted=1' and 'sema-pend: hold ... idx=89' for minutes while the client printed DEVICE. Fix: new svc.op_owed flag. When the pend cap blocks the retry, the pass is marked owed so slot_ops_complete stays 0; the next fresh pass runs the copy as soon as the translation/injection exists. No hold is armed for an owed pass, so an operand that never translates still cannot wedge the pump (the denied path's liveness guarantee is preserved - only the freshness is).
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c89
1 files changed, 74 insertions, 15 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index ff95598..d3ac29c 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -878,6 +878,18 @@ struct sema_svc {
u64 sem256_log; /* 256-byte op trace budget */
u64 op_tr_log; /* operand targeted-resolve budget */
u32 op_tr_pending; /* an operand's targeted scan is in progress */
+ u32 op_owed; /* r540: a denied transfer op
+ * was never re-run because the
+ * per-slot pend cap was hit; the
+ * slot must stay INCOMPLETE so a
+ * later trusted/injected pass
+ * runs it (the r539 5-minute
+ * device-init stall class: the
+ * client's GRCE H2D was denied
+ * while untrusted, capped, then
+ * replay-suppressed forever and
+ * the copy never executed) */
+ u64 op_owed_log; /* r540: bounded owe witness */
u64 copy_watch_log; /* sema_copy_watch log budget */
u64 copy_dst_hold; /* m169: device-dst copies held for
* want of a pin (stale-table guard) */
@@ -11140,20 +11152,54 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
* 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]);
+ entry_idx < SVC_GPFIFO_MAX_BITS) {
+ if (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]);
+ }
+ } else {
+ /*
+ * r540: the cap stopped the
+ * re-hold, but the op is still
+ * owed. Leaving the slot
+ * complete would classify every
+ * later pass as a replay and
+ * suppress the copy forever -
+ * the client waits on a copy
+ * that never ran (the r539
+ * ~5-minute device-init stall:
+ * a GRCE H2D denied while
+ * untrusted, capped at 4 tries,
+ * then replay-suppressed after
+ * the pin arrived). Mark the
+ * pass owed so the slot stays
+ * INCOMPLETE and the next
+ * fresh pass (injected or
+ * translated) executes the
+ * copy. No hold is armed, so a
+ * slot whose trust never arrives
+ * still cannot wedge the pump.
+ */
+ svc.op_owed = 1;
+ if (svc.op_owed_log < 64) {
+ svc.op_owed_log++;
+ pr_info("sema-pend: OWED h=0x%x push=0x%llx idx=%u out=0x%llx in=0x%llx line=%u trusted=%d (cap hit; slot stays incomplete for a fresh retry)\n",
+ ch->h_object, push_va,
+ entry_idx, st.offset_out,
+ st.offset_in,
+ st.line_length,
+ trusted);
+ }
}
}
}
@@ -22049,6 +22095,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc_entry_outcome("decode", ch,
idx, va, len);
svc.op_tr_pending = 0;
+ svc.op_owed = 0;
svc_decode_stream(vgpu, pb,
len, 0,
(allow_ops || injected) &&
@@ -22083,8 +22130,20 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
entry_ident;
ch->slot_ops_done[idx] =
entry_done;
+ /*
+ * r540: an owed
+ * denied op keeps
+ * the slot
+ * incomplete too -
+ * otherwise every
+ * later pass is a
+ * replay and the
+ * op can never run
+ * (see op_owed).
+ */
ch->slot_ops_complete[idx] =
- svc.op_tr_pending ?
+ (svc.op_tr_pending ||
+ svc.op_owed) ?
0 : 1;
ch->slot_ops_hash[idx] =
svc_push_hash(pb,