From 8dce7e59027e8d07ccdf4aa6ac3da02b6e9e9fd9 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 12 Nov 2026 15:39:01 -0500 Subject: vgsp: accept wrapped FB USERD latches and dedup direct channel event posts --- kernel/gsp_rm_emulation.c | 16 +++++++++++++ kernel/gsp_sema_service.c | 57 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c index 4420810..0cef9e7 100644 --- a/kernel/gsp_rm_emulation.c +++ b/kernel/gsp_rm_emulation.c @@ -903,6 +903,22 @@ static int gsp_rm_post_channel_event_common(struct nv_vgpu_device *vgpu, if (!rm->events[i].valid || rm->events[i].h_src != h_src) continue; + /* + * r1780: the directly-associated post is the flood path. The + * X channel's completion edge fires per consumed submission and + * the 48/s burst cap then drops the wake-ups a blocked client is + * waiting for (live: "event burst capped (48/48), dropped + * total=3000", DDX "Failed to idle DMA"). A re-post within + * GSPRM_EVENT_HINT_DEDUP adds no wake-up - the client re-reads + * channel state on any event and the 0.5 s hint re-posts late + * waiters - so apply the dedup the fallback loop already uses. + */ + if (!force && + time_before(jiffies, + rm->events[i].last_post + + GSPRM_EVENT_HINT_DEDUP)) + continue; + gsp_rm_fill_ev_payload(rm, i, payload); { int rc = gsp_rm_send_flags(ctx, gsp_rm_ev_function(), diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 7e389f8..96e135b 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -43835,6 +43835,35 @@ static void svc_gr_util_sweep(struct nv_vgpu_device *vgpu, svc_gr_util_sweep_n(vgpu, ch, 0); } +/* + * Wrap-aware PUT progress for the speculative latch. + * + * A USERD adopted by the FB/VRAM shape scan carries GPFIFO ring indices in + * [0, entries] (the shape gate rejects put > entries; `entries` is the + * wrapped/empty value). Such a producer legitimately wraps entries -> 0: + * h=0x1000013 (ent=65536, latch=65536) later reads put=12, and the raw + * `put > latch` judge saw a decrease, rejected the live block and cleared + * userd_ok - the X/DDX channel then waited forever in "Failed to idle + * DMA". For that class compare modulo entries (entries is a power of two): + * a step of 1..entries/2 is forward progress; anything else (backward + * jump or more than half the ring) keeps the old reject path. + * + * Channels whose PUT is a free-running counter keep the raw comparison: + * the guest-RAM scan (SYS aperture, gr_ram_ring) explicitly admits puts + * far above entries (measured put=12 with entries=2 and put=16 with + * entries=32768), the kick family (0xbfef00xx) authors its own free- + * running count, and a non-power-of-two ring has no usable mask. A + * one-slot ring is excluded too: every put aliases, so there is no + * modulo progress to measure. + */ +static bool svc_userd_put_wrap(const struct svc_channel *ch) +{ + u32 entries = ch->gpfifo_entries; + + return entries >= 2 && !(entries & (entries - 1)) && + ch->userd_as == SVC_APERTURE_FB && !svc_kick_family(ch); +} + static void svc_pump_channels(struct nv_vgpu_device *vgpu) { if (svc_pdb_disc_pending) { @@ -44665,6 +44694,12 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) (!ch->gr_ram_userd_confirmed || (kfam && put < ch->gr_ram_userd_latch_put))) { bool stepped; + bool wrap = svc_userd_put_wrap(ch); + u32 wstep = wrap ? + (put - ch->gr_ram_userd_latch_put) & + (ch->gpfifo_entries - 1) : 0; + bool moved = wrap ? wstep != 0 : + put != ch->gr_ram_userd_latch_put; if (!ch->gr_ram_userd_latch_at) ch->gr_ram_userd_latch_at = jiffies; @@ -44678,10 +44713,25 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) * at ~10 Hz. A forward jump is not evidence of a * stale latch: only a decrease (wrong actor / reused * block) or the 15 s no-advance bound is. + * + * WRAP-FIX: for a ring-index PUT (FB shape scan, + * power-of-two entries) "forward" is modulo entries. + * h=0x1000013 legitimately wrapped 65536 -> 12 and + * the raw compare rejected the live block; see + * svc_userd_put_wrap(). */ - stepped = put > ch->gr_ram_userd_latch_put; + stepped = wrap ? + (wstep && wstep <= ch->gpfifo_entries / 2) : + put > ch->gr_ram_userd_latch_put; if (stepped) { ch->gr_ram_userd_confirmed = true; + if (wrap && + put < ch->gr_ram_userd_latch_put) + pr_info_ratelimited("sema-chan: GR USERD h=0x%x pa=0x%llx speculative latch wrap accepted (put %u latch %u ent %u step %u)\n", + ch->h_object, ch->userd_pa, + put, + ch->gr_ram_userd_latch_put, + ch->gpfifo_entries, wstep); pr_info("sema-chan: GR USERD h=0x%x pa=0x%llx speculative latch CONFIRMED (put %u -> %u)\n", ch->h_object, ch->userd_pa, ch->gr_ram_userd_latch_put, put); @@ -44718,7 +44768,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) } ch->gr_ram_userd_latch_put = put; ch->gr_ram_userd_latch_at = jiffies; - } else if (put != ch->gr_ram_userd_latch_put || + } else if (moved || time_after(jiffies, ch->gr_ram_userd_latch_at + msecs_to_jiffies(15000))) { @@ -44728,8 +44778,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) pr_info("sema-chan: GR USERD h=0x%x pa=0x%llx speculative latch REJECTED (put=%u latch=%u%s)\n", ch->h_object, ch->userd_pa, put, ch->gr_ram_userd_latch_put, - put != ch->gr_ram_userd_latch_put ? - "" : " no advance in 15 s"); + moved ? "" : " no advance in 15 s"); /* * SESSION 153-CONT-5: one stale window must not * kill the pipeline. Remember the rejected -- cgit v1.2.3