summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-09 15:54:23 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-09 15:54:23 -0400
commit70198e7f0cde3768e00f7bbabe94fd26a2fcfa54 (patch)
treece96b8f32145117140009977485108f413e02953
parent90ed3273a6b7b0241954fde6b2d34ab3270d9081 (diff)
downloadopen-iov-70198e7f0cde3768e00f7bbabe94fd26a2fcfa54.tar.gz
open-iov-70198e7f0cde3768e00f7bbabe94fd26a2fcfa54.zip
vgsp-sema: resync a CE channel past residual USERD state on counter reset (ISSUE-0002)
r48: the layout USERD of the second session's rank0 was accepted with the previous session's residual PUT=134; the pump consumed 34 stale slots, then the guest's fresh counter reset PUT to 1 and the pump wrapped: last_get never matched the guest's sequence and the live first push was not processed. The client was later seen pushing 216-byte no-release entries with crel frozen. A fresh channel's first push always publishes PUT<=1 and the client waits for its release before a second push, so a PUT>=2 at discovery is residual: seed last_get past it and resync to slot 0 when the guest's own counter reset drops PUT below put_prev. Clear the wait state once entries are consumed without a reset so later genuine wraps keep the normal wrap path.
-rw-r--r--kernel/gsp_sema_service.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 1637d63..c545242 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -155,6 +155,18 @@ struct svc_channel {
u64 userd_pa;
u32 userd_as; /* NV_ADDR_SYSMEM / NV_ADDR_FBMEM */
bool userd_ok; /* userd_pa reads a plausible put/get */
+ bool userd_wait_fresh;
+ /* ISSUE-0002 r48: the layout USERD was accepted
+ * with a PUT >= 2, i.e. with entries visible at
+ * discovery that can only be the PREVIOUS
+ * session's residual state (a fresh channel's
+ * first push always publishes PUT <= 1, and the
+ * client waits for that push's release before a
+ * second one). last_get was seeded past the
+ * residual entries; the guest's own counter
+ * reset (PUT dropping below put_prev) resyncs
+ * last_get to slot 0 so the live first push is
+ * processed instead of skipped. */
bool logged; /* one state log per channel */
u64 instance_pa;
u64 notifier_pa; /* error notifier: NvNotification slots */
@@ -7830,6 +7842,22 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
ch->userd_pa = ring_pa + 0x10000;
ch->userd_as = ring_ap;
ch->userd_ok = true;
+ /*
+ * ISSUE-0002 (r48): a PUT >= 2 at discovery can only be
+ * the previous session's residual state - the client
+ * always publishes PUT=1 for a fresh channel's first
+ * push and waits for its release before a second. Seed
+ * last_get past the residual entries so the pump does
+ * not consume stale slots and desync from the guest's
+ * counter reset (r48: rank0 accepted PUT=134, the pump
+ * ran 34 stale entries, then the guest reset PUT=1 and
+ * the pump wrapped; the live first push was never
+ * processed). The pump detects the reset as a PUT drop
+ * and resyncs last_get to slot 0.
+ */
+ ch->userd_wait_fresh = p >= 2;
+ if (ch->userd_wait_fresh)
+ ch->last_get = p;
*put = p;
*get = g;
if (ch->ce_index < 32)
@@ -12448,8 +12476,23 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
* processed (a rewind replay of the previous epoch must not
* suppress them).
*/
- if (put < ch->put_prev)
+ if (put < ch->put_prev) {
+ /*
+ * ISSUE-0002 (r48): the layout USERD was accepted with
+ * residual entries (PUT >= 2, userd_wait_fresh); the
+ * guest's fresh counter reset now dropped PUT below
+ * put_prev. Resync last_get to slot 0 so the live
+ * first push is processed instead of skipped (the
+ * guest's push sequence restarts at slot 0). A later
+ * wrap on an established channel is unaffected: the
+ * flag is cleared by this first resync.
+ */
+ if (ch->userd_wait_fresh) {
+ ch->last_get = 0;
+ ch->userd_wait_fresh = false;
+ }
bitmap_zero(ch->slot_done_epoch, SVC_GPFIFO_MAX_BITS);
+ }
ch->put_prev = put;
/*
@@ -13750,6 +13793,14 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
}
spin_unlock_irqrestore(&svc.chan_lock, flags);
+ /*
+ * ISSUE-0002 (r48): a wait-fresh CE channel whose put only
+ * advanced (no counter reset seen) is genuinely running from
+ * the accepted position; drop the fresh-resync state so a
+ * later wrap is handled as a normal wrap.
+ */
+ if (ch->userd_wait_fresh && ch->last_get != get_before)
+ ch->userd_wait_fresh = false;
if (!held && ch->last_get != put)
stalled = true;
else if (!held && ch->last_get != get_before &&