summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-22 19:26:59 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-22 19:26:59 -0400
commit58c2718c2e20d0e9394671e7132150f6905ed12e (patch)
tree26780056f73a836cfa70d999e3a0842eb463f0ff /kernel
parent8f7d265476f233f91b75c0cdfd8b6f3a8ce1afcb (diff)
downloadopen-iov-58c2718c2e20d0e9394671e7132150f6905ed12e.tar.gz
open-iov-58c2718c2e20d0e9394671e7132150f6905ed12e.zip
r505b opdef flush marks the slot complete; bound the slot arrays for large rings
Two fixes for the r505 multikernel livelock (opdef held=18359, expired=61, client at DEVICE forever while the pump looped on ring slot 1): - after the bounded opdef hold expires and svc_opdef_flush delivers the withheld releases, the slot's ops are permanently skipped - but the decode-time bookkeeping had stored slot_ops_complete=0 (op_tr_pending was set when it ran), so every pin-batch rewind replay of the slot re-decoded it, re-set op_tr_pending and re-held the entry forever. Mark the slot complete on flush so a replay suppresses the ops (entry_replay) and the entry consumes normally. - the per-slot op arrays are SVC_GPFIFO_MAX_BITS (1024) but the X/GL channel's ring is 8192 slots: bound every slot-index write/read (entry_ident is zeroed past the array size, so the bookkeeping skips).
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 1e9f981..35abb15 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -21263,10 +21263,17 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
*/
{
u64 ident = (u64)e0 | ((u64)e1 << 32);
- bool same = ident &&
+ /*
+ * r505b: the per-slot op bookkeeping arrays are
+ * SVC_GPFIFO_MAX_BITS (1024) entries; the X/GL
+ * channel's ring is 8192 slots. Bound every slot
+ * index here or a large ring writes out of
+ * bounds.
+ */
+ bool same = ident && idx < SVC_GPFIFO_MAX_BITS &&
ch->slot_ops_ident[idx] == ident;
- entry_ident = ident;
+ entry_ident = (idx < SVC_GPFIFO_MAX_BITS) ? ident : 0;
/*
* A complete prior pass suppresses every op.
* A partial pass (an operand's targeted scan
@@ -21720,7 +21727,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
kfree(pb);
break;
}
- if (svc.op_tr_pending)
+ if (svc.op_tr_pending) {
/*
* Deadline hit: the
* operand never
@@ -21732,6 +21739,34 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
*/
svc_opdef_flush(vgpu, ch,
(u32)idx);
+ /*
+ * r505b: mark the slot's
+ * ops complete. The op was
+ * permanently skipped, but
+ * the decode above stored
+ * complete=0 (op_tr_pending
+ * was set), so every pin-
+ * batch rewind replay of
+ * this slot re-decoded it,
+ * re-set op_tr_pending and
+ * re-held the entry in a
+ * livelock (multikernel on
+ * r505: opdef held=18359,
+ * expired=61, the client
+ * waiting forever while the
+ * pump looped on slot 1).
+ * Nothing is owed after the
+ * flush, so a replay must
+ * skip the ops.
+ */
+ if ((u32)idx <
+ SVC_GPFIFO_MAX_BITS) {
+ ch->slot_ops_complete[idx] =
+ 1;
+ ch->slot_ops_done[idx] =
+ entry_done;
+ }
+ }
rel_seen = (svc_rel_count != rel_n_before);
{
bool fwd_guest_queued;