summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-28 10:52:56 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-28 10:52:56 -0400
commit30f3363286f541198da174cc7508706484dbbee6 (patch)
treec72e3e282e5cb134858c88523eca0c3bd018017f
parentcc1de524d8cea869daacc652108c76f403eb542d (diff)
downloadopen-iov-30f3363286f541198da174cc7508706484dbbee6.tar.gz
open-iov-30f3363286f541198da174cc7508706484dbbee6.zip
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.
-rw-r--r--kernel/gsp_sema_service.c30
1 files 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;
@@ -3467,14 +3470,37 @@ static void svc_handle_map_add(void)
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);
}