summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_phys_booter.c46
-rw-r--r--kernel/gsp_sema_service.c68
-rw-r--r--tools/guest-diag/guest_pin_stream.py15
-rw-r--r--tools/site/pages/Documentation.wiki2
4 files changed, 123 insertions, 8 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index f083c99..72cda10 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -17302,6 +17302,17 @@ gr_page_unmapped:
le64_to_cpu(pv[s + 2]), le64_to_cpu(pv[s + 3]),
le64_to_cpu(pv[s + 4]), le64_to_cpu(pv[s + 5]),
le64_to_cpu(pv[s + 6]), le64_to_cpu(pv[s + 7]));
+ /* m143b: the b (0x130..) and c (0x150..) relocated windows
+ * and the trailing data window, so an aliased/stale PTE
+ * that redirects an engine access into another window is
+ * visible in the same log. */
+ for (s = 0x130; s < 0x180; s += 0x20)
+ pr_info("vgsp-gr: main PT[%03x..%03x]=%016llx %016llx %016llx %016llx %016llx %016llx %016llx %016llx\n",
+ s, s + 7,
+ le64_to_cpu(pv[s]), le64_to_cpu(pv[s + 1]),
+ le64_to_cpu(pv[s + 2]), le64_to_cpu(pv[s + 3]),
+ le64_to_cpu(pv[s + 4]), le64_to_cpu(pv[s + 5]),
+ le64_to_cpu(pv[s + 6]), le64_to_cpu(pv[s + 7]));
for (s = 0x190; s < 0x1a0; s += 8)
pr_info("vgsp-gr: main PT[%03x..%03x]=%016llx %016llx %016llx %016llx %016llx %016llx %016llx %016llx\n",
s, s + 7,
@@ -17909,6 +17920,36 @@ gr_page_unmapped:
GSP_PHYS_PAGE_SIZE);
wrote++;
}
+ /* m143b: unconditional first words of the first page of each
+ * 32-page relocation window (a=0x110000, b=0x130000, c=0x150000)
+ * after the run, so the engine's read/write footprint per window
+ * is provable without relying on the changed-page counter. */
+ {
+ u32 wi;
+
+ for (wi = 0; wi + 1 < req->n_data; wi += 32) {
+ u32 bi = (u32)((req->data[wi].reloc_va -
+ GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >>
+ 12);
+ const u8 *wp;
+ u32 wc = 0, k;
+
+ if (bi >= GSP_PHYS_RMCALL_GR_MAIL_SLOT)
+ continue;
+ wp = gsp_phys_chunk_page_va(
+ &boot_stage.rmcall_gr_bounce, bi);
+ for (k = 0; k < GSP_PHYS_PAGE_SIZE; k += 4)
+ wc += get_unaligned_le32(wp + k);
+ pr_info("vgsp-gr: window[%u] reloc=0x%llx first=%08x %08x %08x %08x changed=%u\n",
+ bi,
+ req->data[wi].reloc_va,
+ get_unaligned_le32(wp),
+ get_unaligned_le32(wp + 4),
+ get_unaligned_le32(wp + 8),
+ get_unaligned_le32(wp + 12),
+ wc != bounce_csum_in[bi]);
+ }
+ }
pr_info("vgsp-gr: bounce copy-out: %u pages written back, %u changed by engine (first bi: %u %u %u %u %u %u %u %u)\n",
wrote, changed, chg[0], chg[1], chg[2], chg[3], chg[4],
chg[5], chg[6], chg[7]);
@@ -17932,8 +17973,9 @@ gr_page_unmapped:
&boot_stage.rmcall_gr_qmdwin, 0);
if (qw)
- pr_info("vgsp-gr: post-OK qmdwin w48..51=%08x %08x %08x %08x\n",
- qw[48], qw[49], qw[50], qw[51]);
+ pr_info("vgsp-gr: post-OK qmdwin w48..59=%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ qw[48], qw[49], qw[50], qw[51], qw[52], qw[53],
+ qw[54], qw[55], qw[56], qw[57], qw[58], qw[59]);
}
ret = 0;
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);
diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py
index 04aba73..739aeca 100644
--- a/tools/guest-diag/guest_pin_stream.py
+++ b/tools/guest-diag/guest_pin_stream.py
@@ -778,10 +778,19 @@ def scan_vmas(fd, pid, out):
try:
for line in maps:
parts = line.split()
- if len(parts) < 6:
+ if len(parts) < 5:
continue
- path = parts[5]
- if not any(p in path for p in VMA_PATHS):
+ # Anonymous mappings (no path field) are the client's UVM sysmem
+ # buffers when the driver maps them without a /dev/zero backing:
+ # the second client's cudaMalloc'd data buffers show up exactly
+ # like that (e.g. 75d7b0000000-75d7b0021000 rw-p 00000000 00:00 0)
+ # and were skipped by the old len<6 check, so their pages never
+ # reached the host and the forwarded launch could not resolve
+ # them (all-zero results for the second client). Accept them at
+ # the high-VA range; the VMA_LO bound and the pagemap present/PFN
+ # filters keep the set to real GPU mappings.
+ path = parts[5] if len(parts) >= 6 else ''
+ if path and not any(p in path for p in VMA_PATHS):
continue
try:
a, b = parts[0].split('-')
diff --git a/tools/site/pages/Documentation.wiki b/tools/site/pages/Documentation.wiki
index 79f2cec..cab7408 100644
--- a/tools/site/pages/Documentation.wiki
+++ b/tools/site/pages/Documentation.wiki
@@ -24,7 +24,7 @@ This is the index of the Open-IOV wiki. If you are new, read '''[[Project Status
* [[CUDA Userspace Driver]] — the <code>libcuda.so</code> deep dive
* [[The Execution Frontier]] — the GR compute-launch chain and its current wall
-== Firmware interoperability ==
+== Firmware and reverse engineering ==
* [[GSP 570.144W Firmware Analysis]] — how the 28.5 MB image was decompiled and mapped
* [[Address Reference]] — firmware-side address tables
* [[risc-v-gsp-rm-debugger]] — the firmware runtime workbench (hooks, watchpoints, sessions)