diff options
| -rw-r--r-- | kernel/gsp_sema_service.c | 53 |
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 && |
