summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c90
1 files changed, 89 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 611bb35..3b56c36 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -392,6 +392,21 @@ struct svc_pb_hit {
static struct svc_pb_hit svc_pb[SVC_PB_MAX];
static u32 svc_pb_n;
static u32 svc_ring_n;
+
+/*
+ * ISSUE-0002 multi-session: every translation source below (the merged scan
+ * map, the pinned push-buffer pairs, the discovered page-directory latch and
+ * the rebuilt direct_base) is learned from the live client's own page tables
+ * and push content. When the last channel of a client closes, a later client
+ * runs in a new UVM VA space that reuses the same VAs backed by new pages;
+ * anything learned from the previous session then answers for the wrong
+ * session (resolutions miss, releases queue in svc_pending and the new
+ * client spins). One clean boot always works, so make the next session look
+ * like one: when the channel set empties, request a flush and let the next
+ * rebuild start from the same empty state as a fresh boot.
+ */
+static u8 svc_sess_flush;
+static unsigned long svc_ring_done; /* CE ranks whose ring is pinned (session state) */
static u8 svc_pb_passes;
static u64 svc_pb_last;
/*
@@ -966,6 +981,19 @@ void gsp_sema_service_channel_del(u32 h_object)
break;
}
}
+ /*
+ * ISSUE-0002: when the last channel closes, the next client is a new
+ * session in a new UVM VA space; its discovery state must not inherit
+ * this session's map/pins/page-directory latch. Request the flush
+ * here; it executes at the next rebuild (the only writer of that
+ * state) just like a fresh boot would start empty.
+ */
+ for (i = 0; i < SVC_MAX_CHANNELS; i++) {
+ if (svc.chan[i].valid)
+ break;
+ }
+ if (i == SVC_MAX_CHANNELS)
+ svc_sess_flush = 1;
spin_unlock_irqrestore(&svc.chan_lock, flags);
/*
@@ -2889,6 +2917,8 @@ static int svc_map_lookup_range(u64 gpu_va, u32 from, u32 to, u64 *pa)
return -ENOENT;
}
+static void svc_session_flush(void); /* defined next to the pending queue */
+
static void svc_rebuild(struct nv_vgpu_device *vgpu)
{
static u8 *buf;
@@ -2899,6 +2929,15 @@ static void svc_rebuild(struct nv_vgpu_device *vgpu)
u32 best_count = 0;
u32 old_n;
+ /*
+ * ISSUE-0002: executed only between client sessions (the last
+ * channel has closed), so no live session loses translations.
+ */
+ if (svc_sess_flush) {
+ svc_sess_flush = 0;
+ svc_session_flush();
+ }
+
if (!buf) {
buf = kmalloc(SEMA_PAGE_SIZE, GFP_KERNEL);
if (!buf)
@@ -6251,6 +6290,55 @@ static void svc_pending_add(u64 va, u32 payload, u32 op)
}
/*
+ * ISSUE-0002: reset every discovery artifact that was learned from the
+ * client that just closed (see svc_sess_flush). Runs at the top of
+ * svc_rebuild, after the last channel of the previous session unregistered,
+ * so the next client re-discovers its own map/pins/page directory from its
+ * own content exactly like a fresh boot - which is the configuration that
+ * is reproducibly green. Held releases belong to waiters that no longer
+ * exist; drop them instead of resolving them against the next session.
+ */
+static void svc_session_flush(void)
+{
+ unsigned long flags;
+ u32 i;
+
+ svc.map_n = 0;
+ svc_pb_n = 0;
+ svc_pd_found = 0;
+ svc_pd_attempts = 0;
+ svc_pd_best = 0;
+ svc_pd_cands = 0;
+ svc_pd_ev_hash = 0;
+ svc.direct_base = 0;
+ svc_pending_n = 0;
+ svc_pending_next = 0;
+ svc_pool_pa_n = 0;
+ svc_pool_pa_next = 0;
+ svc_retry_next = 0;
+ svc_fwd_rel_n = 0;
+ svc_grce_dst_ring_next = 0;
+ svc_ring_done = 0;
+ memset(svc_retry_q, 0, sizeof(svc_retry_q));
+ memset(svc_pool_pa, 0, sizeof(svc_pool_pa));
+ memset(svc_fwd_rel, 0, sizeof(svc_fwd_rel));
+ memset(svc_grce_dst_ring, 0, sizeof(svc_grce_dst_ring));
+ for (i = 0; i < SVC_VAS_SLOTS; i++) {
+ if (svc_vas[i].data)
+ kfree(svc_vas[i].data);
+ svc_vas[i].data = NULL;
+ svc_vas[i].va_page = 0;
+ }
+ svc_vas_n = 0;
+ memset(svc.lat, 0, sizeof(svc.lat));
+ spin_lock_irqsave(&svc.vas_lock, flags);
+ for (i = 0; i < SVC_MAX_VASPACES; i++)
+ svc.vas[i].valid = false;
+ spin_unlock_irqrestore(&svc.vas_lock, flags);
+ pr_info("sema-svc: session flush (all channels closed): discovery state reset for the next client\n");
+}
+
+/*
* Loud, bounded telemetry for a starved deferred release (ISSUE-0001).
* Called from the two "no translation yet, keep" paths of
* svc_apply_pending() with an incremented try count; logs at 4/64/1024
@@ -13431,7 +13519,7 @@ static int svc_thread(void *arg)
svc_handle_map_add();
svc_handle_chan_dump(vgpu);
- if (!svc.direct_base ||
+ if (svc_sess_flush || !svc.direct_base ||
time_after(jiffies,
(unsigned long)(svc.last_build + 10 * HZ)))
svc_rebuild(vgpu);