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.c68
1 files changed, 66 insertions, 2 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 7d690ab..0a97cea 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -928,6 +928,34 @@ static int svc_write_ap(struct nv_vgpu_device *vgpu, u64 addr, u32 aperture,
static bool svc_gr_content_rearm;
/*
+ * m148 (second-client wedge): re-arm the per-rank one-shot ring/push-buffer
+ * latches for a (re-)registered channel. The guest driver rebuilds the GSP
+ * session for every client context and RM reuses the same object handles and
+ * channel ranks across sessions. The ISSUE-0002 session flush only runs on
+ * the last-channel-closed transition, so a second session that re-registers
+ * the same handles while the first session's entries are still present (or
+ * before the deferred flush executes) inherits the previous session's latch
+ * bits. The CE/GR ring autopin and the push-buffer pairing then never re-run,
+ * the new session's ring stays untranslated (svc_lookup fails for its GPFIFO
+ * VA), the pump counts the entries as nomap and the guest spins forever in
+ * uvm_tracker_wait_for_entry waiting for its channel-creation push release -
+ * the second-client wedge. Both autopin paths and the pairing are
+ * content-validated (entry0 must parse; a discovered base must carry this
+ * channel's slot), so re-arming is safe and idempotent within a session.
+ */
+static void svc_chan_rearm_rank(struct svc_channel *ch)
+{
+ if (!ch || !ch->valid)
+ return;
+ if (ch->engine_type) {
+ clear_bit(ch->ce_index, &svc_ring_done);
+ clear_bit(ch->ce_index, &svc_pb_done);
+ } else {
+ clear_bit(ch->gr_index, &svc_gr_ring_done);
+ }
+}
+
+/*
* Register a guest channel. Called from the GSP-RM emulation when the guest
* driver allocates a channel (the allocation carries the GPFIFO GPU VA, its
* entry count and the guest-physical USERD/instance blocks), and dropped when
@@ -1050,6 +1078,13 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc)
spin_unlock_irqrestore(&svc.chan_lock, flags);
if (ch) {
+ /*
+ * m148: force the ring/push-buffer discovery latches for this
+ * rank to re-run for the (possibly new) session, so the new
+ * ring is translated from its own content instead of inheriting
+ * the previous session's one-shot state (second-client wedge).
+ */
+ svc_chan_rearm_rank(ch);
svc.last_chan_reg = jiffies;
pr_info("sema-svc: channel 0x%x registered gpfifo=0x%llx entries=%u userd=0x%llx eng=%u cid=%u notif=0x%llx\n",
desc->h_object, desc->gpfifo_va, desc->gpfifo_entries,
@@ -1063,7 +1098,6 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc)
/* P6b wave-1.5 hold state is defined with the forwarding section below. */
static void svc_fwd_hold_abort(u32 h_object);
-
/*
* P6b wave-2 inline software fallback for a withheld (skipped) candidate;
* defined with the forwarding section below. Service-thread only.
@@ -6499,6 +6533,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
u32 cur = 0;
int pending = 0;
bool have_cur = false;
+ bool pool_stale_drop = false;
bool inc, inc_apply = false;
if (page_pa)
@@ -6646,6 +6681,8 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
have_cur = true;
if (st.sem_payload > cur)
pending = 1;
+ else
+ pool_stale_drop = true;
}
/*
* ISSUE-0002 r70: the residue rule
@@ -6657,8 +6694,22 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
* so a submissions-based freshness
* test misses the re-decode; this
* flag does not.
+ *
+ * r101: a read the stale-drop path
+ * discarded (payload <= cur, nothing
+ * applied or deferred) must NOT set
+ * the flag. The reused pool page of
+ * a fresh session reads the previous
+ * session's residue (cur > payload)
+ * BEFORE the first genuine release is
+ * translated; that read used to set
+ * the flag and every later residue
+ * release was then silently dropped
+ * (r99/r100: pay=1 cur=2 dropped, the
+ * client spins at DEVICE).
*/
- if (!rrc2 && svc_pool_sem_va(sem_va) && ch)
+ if (!rrc2 && svc_pool_sem_va(sem_va) && ch &&
+ !pool_stale_drop)
ch->pool_rel_seen = true;
}
@@ -12500,6 +12551,8 @@ static void svc_gr_req_bridge_fallback(struct nv_vgpu_device *vgpu)
* forwarding can never overlap; the caller engages the release hold on a
* true return. Service-thread only.
*/
+static void svc_handle_map_add(void);
+
static bool svc_gr_request(struct nv_vgpu_device *vgpu,
const struct svc_channel *ch)
{
@@ -12540,6 +12593,17 @@ static bool svc_gr_request(struct nv_vgpu_device *vgpu,
svc_gr_bridge_fallback(vgpu);
return false;
}
+ /*
+ * m143: drain the host injection queue before resolving the launch's
+ * pages. The watcher's pins for the client's a/b/c buffers can land
+ * between the service loop's map_add drain and this capture; the fill
+ * then misses them, nothing is relocated, and the win0 param page the
+ * SM reads keeps the driver's original guest VAs (the second client's
+ * all-zero results, rk1: candidate[0..2] -> 0 new pages). Draining
+ * here closes that window; svc_handle_map_add() runs on this same
+ * service thread, so there is no race with the loop's own drain.
+ */
+ svc_handle_map_add();
rc = svc_gr_req_fill(vgpu, ch);
if (rc) {
clear_bit_unlock(SVC_FWD_INFLIGHT, &svc_fwd_state);