summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_phys_booter.c152
-rw-r--r--kernel/gsp_sema_service.c50
2 files changed, 195 insertions, 7 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 8c9a2eb..5850f00 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -4959,6 +4959,96 @@ static u32 gsp_phys_engine_type_from_errstr(const char *err)
}
/*
+ * SESSION 153-CONTINUED-12: last published GR launch identity, set by the
+ * single-inflight submit path so a PBDMA fault dump can name the entry the
+ * PBDMA is stuck on (block length in dwords, guest push VA, object handle).
+ */
+static u32 gsp_phys_gr_last_words;
+static u32 gsp_phys_gr_last_h;
+static u64 gsp_phys_gr_last_push_va;
+
+/*
+ * SESSION 153-CONTINUED-12: on a robust-channel PBDMA error (exceptType
+ * 0x20) dump every PBDMA's latched instruction state and, for the PBDMA
+ * whose PB_FETCH sits inside the module pushbuffer page, the raw block words
+ * around the fetch point plus the whole block with indices. The latched
+ * raw instruction (HDR_SHADOW) can be matched against the block dump to
+ * name the exact word the PBDMA rejected ("invalid method encoding"); the
+ * fetch position shows how far the walk got. Read-only MMIO + a racy read
+ * of the pb page (best effort, diagnostic only); bounded per boot.
+ */
+#define GSP_PHYS_PBDMA_DUMP_MAX 6u
+
+static const char *gsp_phys_pbdma_type_name(u32 t)
+{
+ static const char *names[8] = { "SSDM", "INC", "STORE_SDM", "NON_INC",
+ "IMMD", "INC_ONCE", "USE_SDM", "END_SEG" };
+
+ return names[t & 7u];
+}
+
+static void gsp_phys_pbdma_fault_dump(u32 chid)
+{
+ static u32 dump_n;
+ void __iomem *bar0 = gsp_phys_gpu_bar0();
+ u64 pb_va = boot_stage.rmcall_va_pb;
+ u32 i;
+
+ if (!bar0 || !gsp_phys_gr_last_words || dump_n >= GSP_PHYS_PBDMA_DUMP_MAX)
+ return;
+ dump_n++;
+ pr_info("vgsp-gr: PB-FAULT-DUMP chid=%u last_block words=%u h=0x%x push=0x%llx pb_va=0x%llx\n",
+ chid, gsp_phys_gr_last_words, gsp_phys_gr_last_h,
+ gsp_phys_gr_last_push_va, pb_va);
+ for (i = 0; i < 12; i++) {
+ u32 b = 0x40000u + i * 0x2000u;
+ u32 intr0 = readl(bar0 + b + 0x108u);
+ u32 gpf = readl(bar0 + b + 0x050u);
+ u32 pbf = readl(bar0 + b + 0x054u);
+ u32 pbfhi = readl(bar0 + b + 0x058u);
+ u32 pbhd = readl(bar0 + b + 0x084u);
+ u32 pbcnt = readl(bar0 + b + 0x088u);
+ u32 pbd0 = readl(bar0 + b + 0x08cu);
+ u32 hdrsh = readl(bar0 + b + 0x118u);
+ u32 fetch64 = ((pbfhi & 0xffu) << 32) | (pbf & ~3u);
+
+ if (!intr0 && !pbf && !hdrsh && !pbhd)
+ continue;
+ pr_info("vgsp-gr: PB-FAULT-DUMP P%u intr0=%08x gpf=%u pbfetch=0x%llx len=%u hdr=%08x(%s m=0x%x cnt=%u sub=%u) cnt=%08x data0=%08x shadow=%08x\n",
+ i, intr0, gpf, fetch64, pbfhi >> 11,
+ hdrsh, gsp_phys_pbdma_type_name(hdrsh >> 29),
+ (hdrsh & 0x1fffu) << 2,
+ (hdrsh >> 16) & 0xfffu, (hdrsh >> 13) & 7u,
+ pbcnt, pbd0, hdrsh);
+ }
+ {
+ struct gsp_phys_boot_chunk *pbch =
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_PB];
+ u32 *pw = pbch->pages ? gsp_phys_chunk_page_va(pbch, 0) : NULL;
+
+ if (pw && pb_va) {
+ u32 n = gsp_phys_gr_last_words < 384u ?
+ gsp_phys_gr_last_words : 384u;
+ u32 w;
+
+ for (w = 0; w < n; w += 16) {
+ u32 m;
+
+ pr_info("vgsp-gr: PB-FAULT-DUMP pb[%3u]= %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ w, pw[w], w + 1 < n ? pw[w + 1] : 0,
+ w + 2 < n ? pw[w + 2] : 0, w + 3 < n ? pw[w + 3] : 0,
+ w + 4 < n ? pw[w + 4] : 0, w + 5 < n ? pw[w + 5] : 0,
+ w + 6 < n ? pw[w + 6] : 0, w + 7 < n ? pw[w + 7] : 0,
+ w + 8 < n ? pw[w + 8] : 0, w + 9 < n ? pw[w + 9] : 0,
+ w + 10 < n ? pw[w + 10] : 0, w + 11 < n ? pw[w + 11] : 0,
+ w + 12 < n ? pw[w + 12] : 0, w + 13 < n ? pw[w + 13] : 0,
+ w + 14 < n ? pw[w + 14] : 0, w + 15 < n ? pw[w + 15] : 0);
+ }
+ }
+ }
+}
+
+/*
* Note every consumed 0x1006 in the bounded last-4 ring, advance the fault
* epoch (the relay submit snapshot compares against it) and log the designed
* observation line when the fault relay is armed. Decoding and counting are
@@ -4978,6 +5068,8 @@ static void gsp_phys_fault_observe(const struct gsp_phys_rx_record *rec,
pr_info_ratelimited("vgsp-fault: func=0x1006 seq=%u exceptType=0x%x runlistId=%u chid=%u prevXid=0x%x errString=\"%s\"\n",
rec->seq_num, out->except_type, out->runlist_id,
out->chid, out->prev_xid, out->err);
+ if (out->except_type == 0x20u)
+ gsp_phys_pbdma_fault_dump(out->chid);
}
/* Note every consumed 0x1020 for the C3 corroboration ring. */
@@ -15259,10 +15351,24 @@ static int gsp_phys_rmcall_publish_locked(void __iomem *bar0, u64 pb_gpu_va,
* site passes false, so the default COPY0 ladder emits the same bytes as
* before.
*/
-static int gsp_phys_rmcall_ce_submit_locked(void __iomem *bar0, u64 src_va,
- u64 dst_va, u64 sem_va, u32 bytes,
- u32 sem_payload, bool gr,
- struct gsp_phys_rmcall_ce_submit *out)
+/*
+ * SESSION 153-CONTINUED-12: pb_off selects where in the module pushbuffer
+ * page the method block is written and fetched from. The warm-semaphore
+ * probe (gsp_phys_rmcall_gr_sem_push_locked) uses the upper half so it can
+ * never overwrite a forwarded launch's pending method block: measured with
+ * the PBDMA dump, the probe's 10-dword block landing on words 0..9 of a
+ * pending 139-word 3D replay made the PBDMA walk the probe's
+ * SET_OBJECT/REPORT_SEM tail and then decode the replay window's operand
+ * 0x00230200 as an instruction -> PBENTRY on chid 4 and no retire. Every
+ * forwarded GR/CE block stays at offset 0 (<= 512 dwords = 0x800 bytes by
+ * the GSP_PHYS_RMCALL_GR_METHOD_WORDS bound).
+ */
+static int gsp_phys_rmcall_ce_submit_off_locked(void __iomem *bar0,
+ u64 src_va, u64 dst_va,
+ u64 sem_va, u32 bytes,
+ u32 sem_payload, bool gr,
+ u32 pb_off,
+ struct gsp_phys_rmcall_ce_submit *out)
{
struct gsp_phys_boot_chunk *pb =
&boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_PB];
@@ -15291,11 +15397,16 @@ static int gsp_phys_rmcall_ce_submit_locked(void __iomem *bar0, u64 src_va,
if (!bar0 || !boot_stage.rmcall_token || !bytes ||
bytes > GSP_PHYS_RMCALL_COPY_SIZE)
return -EINVAL;
+ if (pb_off & 3u)
+ return -EINVAL;
pb_gpu_va = boot_stage.rmcall_va_pb;
if (!pb_gpu_va || (pb_gpu_va & 3))
return -EIO;
- pb_va = gsp_phys_chunk_page_va(pb, 0);
+ if (!gsp_phys_chunk_page_va(pb, 0) || pb_off > GSP_PHYS_PAGE_SIZE)
+ return -EIO;
+ pb_va = (u32 *)((u8 *)gsp_phys_chunk_page_va(pb, 0) + pb_off);
+ pb_gpu_va += pb_off;
ring_va = gsp_phys_chunk_page_va(ring, 0);
userd = gsp_phys_chunk_page_va(userd_c, 0);
if (!pb_va || !ring_va || !userd ||
@@ -15316,9 +15427,22 @@ static int gsp_phys_rmcall_ce_submit_locked(void __iomem *bar0, u64 src_va,
dst_va, bytes,
sem_payload);
+ if (pb_off + words * 4 > GSP_PHYS_PAGE_SIZE)
+ return -EIO;
+
return gsp_phys_rmcall_publish_locked(bar0, pb_gpu_va, words, out);
}
+static int gsp_phys_rmcall_ce_submit_locked(void __iomem *bar0, u64 src_va,
+ u64 dst_va, u64 sem_va, u32 bytes,
+ u32 sem_payload, bool gr,
+ struct gsp_phys_rmcall_ce_submit *out)
+{
+ return gsp_phys_rmcall_ce_submit_off_locked(bar0, src_va, dst_va,
+ sem_va, bytes, sem_payload,
+ gr, 0u, out);
+}
+
/*
* H1 stage-4 GR verification: one GR semaphore release on the ladder channel,
* shared by stage 4's GR branch and the debugfs trigger 9 re-run. The caller
@@ -15376,12 +15500,22 @@ static int gsp_phys_rmcall_gr_sem_push_locked(void __iomem *bar0)
unsigned long deadline;
int ret;
- ret = gsp_phys_rmcall_ce_submit_locked(bar0, GSP_PHYS_RMCALL_VA_SRC,
+ /*
+ * SESSION 153-CONTINUED-12: this probe runs while a forwarded launch
+ * may still be pending in the same pushbuffer page. It must not land
+ * on words 0.. of that page: measured PB-FAULT-DUMP shows the probe's
+ * 10-dword block overwriting a pending 139-word 3D replay's head, so
+ * the PBDMA walks the probe then decodes a replay operand as an
+ * instruction (PBENTRY, no retire). Use the upper half (0x800); the
+ * forwarded block is bounded to 512 dwords = 0x800 bytes.
+ */
+ ret = gsp_phys_rmcall_ce_submit_off_locked(bar0,
+ GSP_PHYS_RMCALL_VA_SRC,
GSP_PHYS_RMCALL_VA_DST,
GSP_PHYS_RMCALL_VA_SEM,
GSP_PHYS_RMCALL_COPY_SIZE,
GSP_PHYS_RMCALL_SEM_PAYLOAD, true,
- &sub);
+ 0x800u, &sub);
if (ret) {
pr_err("vgsp-boot: rm-call: GR submission refused before the doorbell (%d)\n",
ret);
@@ -20708,6 +20842,10 @@ gr_page_unmapped:
ch_sem_va, want_ch,
win3d, win3d_n);
memcpy(gsp_phys_chunk_page_va(pb, 0), methods, words * 4);
+ /* SESSION 153-CONTINUED-12: identify this block to a later PBDMA dump. */
+ WRITE_ONCE(gsp_phys_gr_last_words, words);
+ WRITE_ONCE(gsp_phys_gr_last_h, req->h_object);
+ WRITE_ONCE(gsp_phys_gr_last_push_va, req->push_va);
pr_info("vgsp-gr: qmd w0..3=%08x %08x %08x %08x w4..7=%08x %08x %08x %08x w23..25=%08x %08x %08x w32/33=%08x %08x w48/49=%08x %08x\n",
qmd[0], qmd[1], qmd[2], qmd[3], qmd[4], qmd[5], qmd[6], qmd[7],
qmd[23], qmd[24], qmd[25], qmd[32], qmd[33], qmd[48], qmd[49]);
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index ce008d6..ac6f392 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -12689,6 +12689,56 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
}
}
+ /*
+ * SESSION 153-CONTINUED-12: attach on the draw marker itself.
+ *
+ * The section recogniser below needs the sticky C597 bind
+ * (svc_gl_att_h) that the boot-class GLX init push carries. On a
+ * boot where the class is bound channel-side (inside the emulated
+ * RM channel setup) and no decoded push re-emits SET_OBJECT C597,
+ * every draw-shaped push is dropped and no 3D replay ever runs.
+ * Adopt the first trusted push that carries an NVC597_BEGIN IMMD
+ * (op 4, addr 0x1618, subchannel 0) as the attached channel; the
+ * per-pass gl_win_start tracker then runs over that same push from
+ * its start, exactly as it does after an explicit bind, so the
+ * window keeps the pre-BEGIN state methods (vertex stream bases,
+ * colour target, constant-buffer selectors).
+ */
+ if (gsp_sema_gl_xlate && !ch->engine_type && trusted &&
+ !svc_gl_att_h) {
+ u32 o2 = 0;
+
+ while (o2 + 4 <= len) {
+ u32 h2, op2, cnt2, sc2, ad2;
+
+ memcpy(&h2, buf + o2, 4);
+ op2 = (h2 >> 29) & 0x7;
+ cnt2 = (h2 >> 16) & 0xfff;
+ sc2 = (h2 >> 13) & 0x7;
+ ad2 = (h2 & 0x1fff) << 2;
+ if (op2 == 4 && ad2 == 0x1618 && sc2 == 0) {
+ svc_gl_att_h = ch->h_object;
+ svc_gl_att_subch = 0;
+ if (gsp_sema_dbg && svc_gl_draw_log < 64) {
+ svc_gl_draw_log++;
+ pr_info("sema-gl: attach-on-BEGIN h=0x%x push=0x%llx off=0x%x (no explicit C597 bind seen)\n",
+ ch->h_object, push_va, o2);
+ }
+ break;
+ }
+ if (op2 == 4 || op2 == 7) {
+ o2 += 4;
+ continue;
+ }
+ if ((op2 == 1 || op2 == 3 || op2 == 5) && cnt2 &&
+ cnt2 <= 0xfff && o2 + 4 + cnt2 * 4 <= len) {
+ o2 += 4 + cnt2 * 4;
+ continue;
+ }
+ o2 += 4;
+ }
+ }
+
while (off + 4 <= len) {
u32 hdr = 0, op, count, subch, addr;
u32 v0 = 0, v1 = 0, v2 = 0, v3 = 0, v4 = 0;