diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-23 10:29:47 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-23 10:29:47 -0400 |
| commit | e1b07df46b10f64dfcf93e53ee966c905d3e6e16 (patch) | |
| tree | b18afc81efd6c83db8b6bee9f749e6e2540bfe5c /kernel/gsp_sema_service.c | |
| parent | 8c30b1108dc5b368ccd5611076c0aa7dafecd892 (diff) | |
| download | open-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.c | 89 |
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, |
