diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_sema_service.c | 90 |
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); |
