From 30f3363286f541198da174cc7508706484dbbee6 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 28 Sep 2026 10:52:56 -0400 Subject: sema: re-run recent ring entries when a translation is replaced A pin injected after the pump consumed pushes that release through that VA resolved against the old (or bogus) translation, so the releases were compared as stale against the old page's values and dropped - a new client that maps fresh pages at the same VAs then waits forever. Rewind every channel's last_get by 8 ring entries on injection so the pump re-reads those pushes under the new translation; the release and fill application paths are forward-progress guarded and idempotent, so re-execution is safe. The handler runs in the service thread, which also runs the pump, so no pass can be in flight during the rewind. Diagnosed from cdt4: its tracker releases were consumed while the pin still pointed at the previous cdt's page (value 1), so payload <= cur and every release was dropped as stale; re-pinning afterwards could not resurrect them because the ring entries had already been consumed. --- kernel/gsp_sema_service.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 40926ee..020023a 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -3452,11 +3452,14 @@ static u64 map_add_pa; static u64 map_add_len; static u32 map_add_ap; static bool map_add_pending; +#define SVC_PIN_REWIND 8 static void svc_handle_map_add(void) { u32 ap = map_add_ap ? map_add_ap : SVC_APERTURE_SYS; + unsigned long flags; u64 off; + int i; if (!map_add_pending) return; @@ -3466,15 +3469,38 @@ static void svc_handle_map_add(void) svc_pin_store(map_add_va + off, map_add_pa + off, ap); svc_lat_store(map_add_va + off, map_add_pa + off, ap); } + /* + * A translation can be replaced after the pump already consumed + * pushes that release through it (a new client maps new physical + * pages at the same VA, or the first translation was wrong): the + * releases resolved against the old page, compared as stale against + * its values, and were dropped. Rewind every channel a few ring + * entries so those pushes are re-read under the new translation; + * the release/fill application paths are forward-progress guarded, + * so re-executing them is idempotent. + */ + spin_lock_irqsave(&svc.chan_lock, flags); + for (i = 0; i < SVC_MAX_CHANNELS; i++) { + struct svc_channel *ch = &svc.chan[i]; + u32 get; + + if (!ch->valid || !ch->gpfifo_entries) + continue; + get = ch->last_get; + ch->last_get = (get >= SVC_PIN_REWIND) ? get - SVC_PIN_REWIND : + ch->gpfifo_entries - (SVC_PIN_REWIND - get); + } + spin_unlock_irqrestore(&svc.chan_lock, flags); + /* * Releases that missed translation before this injection may be * applicable now: keep the fast full-RAM sweep armed for a few * seconds so they land without waiting for an unrelated stall. */ svc.fast_force_until = jiffies + 10 * HZ; - pr_info("sema-svc: injected mapping va=0x%llx -> pa=0x%llx len=0x%llx (%s)\n", + pr_info("sema-svc: injected mapping va=0x%llx -> pa=0x%llx len=0x%llx (%s), rewound channels by %u\n", map_add_va, map_add_pa, map_add_len, - ap == SVC_APERTURE_FB ? "vidmem" : "sysmem"); + ap == SVC_APERTURE_FB ? "vidmem" : "sysmem", SVC_PIN_REWIND); map_add_pending = false; complete(&map_add_done); } -- cgit v1.2.3