summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 &&