summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-06 23:05:02 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-06 23:05:02 -0400
commitf27e38956df2705d797f0639c8a851b0c3c41209 (patch)
tree73e85fdb6d50ee857860088d7b9eccea85fd41df
parent00765678d59423669fcad6fe56cce9be9bb352e6 (diff)
downloadopen-iov-f27e38956df2705d797f0639c8a851b0c3c41209.tar.gz
open-iov-f27e38956df2705d797f0639c8a851b0c3c41209.zip
vgsp: mode 35 m64 - forced module-sem release discriminant + fallback poll fix + post-mortem dumps
m63 (E2 lane enable) got the forwarded QMD into SKED: CWD_TABLE_0 left the cold value, CWD_TABLE_1 carried the QMD id (0x1070), SKED_ACTIVITY fired, FECS_CURRENT_CTX showed V7's instance with VALID=1 - but the release write never landed (relw=5) and no engine fault is logged. m64 discriminates 'engine completed but the shadow release was lost' from 'engine never completed': param gsp_phys_rmcall_gr_rel_mod=1 forces QMD release0 to the module window-0 semaphore with a distinct payload (0x600df00d) and polls the SEM chunk. Also fixes the latent fallback (it set no poll source, so a module-sem release could never complete) and dumps the full QMD w2..w15 + the guest release page words in the post-mortem.
-rw-r--r--kernel/gsp_phys_booter.c58
-rw-r--r--kernel/gsp_phys_gpu.c22
-rw-r--r--kernel/gsp_phys_gpu.h4
3 files changed, 81 insertions, 3 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 67ade76..40dfca3 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -15090,6 +15090,12 @@ EXPORT_SYMBOL_GPL(gsp_phys_backend_guest_ce_copy);
/* PCAS(4) + REPORT_SEM(8). */
#define GSP_PHYS_RMCALL_GR_TAIL_WORDS 12u
#define GSP_PHYS_RMCALL_GR_QMD_REL_PAYLOAD GSP_PHYS_RMCALL_SEM_PAYLOAD
+/*
+ * m64: the forced module-sem release needs a payload distinct from the
+ * stage-4 sem value (GSP_PHYS_RMCALL_SEM_PAYLOAD = 0xc0ffee01), otherwise
+ * the poll would match the pre-existing word without an engine write.
+ */
+#define GSP_PHYS_RMCALL_GR_QMD_REL_MOD_PAYLOAD 0x600df00du
#define GSP_PHYS_RMCALL_GR_SEM_PAYLOAD 0xc0ffee02u
/*
* PCAS launcher (bisect): the driver's non-IQ2M path schedules a QMD with
@@ -15722,8 +15728,9 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
if (((qmd[4] >> 10) & 1)) {
u32 red_en = (qmd[24] >> 26) & 1;
u32 one_word = (qmd[24] >> 31) & 1;
+ bool rel_mod = gsp_phys_rmcall_gr_rel_mod_value() != 0;
- if (req->rel_hpa && one_word && !red_en &&
+ if (!rel_mod && req->rel_hpa && one_word && !red_en &&
n_shadow < GSP_PHYS_RMCALL_GR_SHADOW_PAGES) {
u64 sh_va = 0;
@@ -15750,9 +15757,20 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
qmd[24] = (qmd[24] & 0xffffff00u) |
((u32)(GSP_PHYS_RMCALL_VA_SEM >> 32) &
0xffu);
- qmd[25] = GSP_PHYS_RMCALL_GR_QMD_REL_PAYLOAD;
- want_qmd = GSP_PHYS_RMCALL_GR_QMD_REL_PAYLOAD;
+ qmd[25] = rel_mod ?
+ GSP_PHYS_RMCALL_GR_QMD_REL_MOD_PAYLOAD :
+ GSP_PHYS_RMCALL_GR_QMD_REL_PAYLOAD;
+ want_qmd = qmd[25];
qmd_rel = true;
+ /*
+ * m64: the module-sem fallback must poll the SEM chunk,
+ * otherwise a completed QMD is unobservable (the poll
+ * only reads qmd_rel_hpa).
+ */
+ qmd_rel_hpa = (u64)gsp_phys_chunk_page_dma(
+ &boot_stage.rmcall_chunks
+ [GSP_PHYS_RMCALL_BUF_SEM], 0);
+ qmd_rel_off = 0;
}
}
@@ -16259,6 +16277,40 @@ gr_page_unmapped:
"not-run (sentinel intact)" :
"ran (page overwritten)",
qmdwin_note);
+ {
+ u8 *qp = qmd_dst_mem ? qmd_dst_mem :
+ (req->qmd_hpa ?
+ (u8 *)__va(req->qmd_hpa) :
+ NULL);
+
+ if (qp)
+ pr_info("vgsp-gr: post-mortem qmd w2..w15 = %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ get_unaligned_le32(qp + 8),
+ get_unaligned_le32(qp + 12),
+ get_unaligned_le32(qp + 16),
+ get_unaligned_le32(qp + 20),
+ get_unaligned_le32(qp + 24),
+ get_unaligned_le32(qp + 28),
+ get_unaligned_le32(qp + 32),
+ get_unaligned_le32(qp + 36),
+ get_unaligned_le32(qp + 40),
+ get_unaligned_le32(qp + 44),
+ get_unaligned_le32(qp + 48),
+ get_unaligned_le32(qp + 52),
+ get_unaligned_le32(qp + 56),
+ get_unaligned_le32(qp + 60));
+ }
+ if (req->rel_hpa)
+ pr_info("vgsp-gr: post-mortem release page hpa=0x%llx off=0x%x w0..7 = %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ req->rel_hpa, req->rel_off,
+ get_unaligned_le32((u8 *)__va(req->rel_hpa)),
+ get_unaligned_le32((u8 *)__va(req->rel_hpa) + 4),
+ get_unaligned_le32((u8 *)__va(req->rel_hpa) + 8),
+ get_unaligned_le32((u8 *)__va(req->rel_hpa) + 12),
+ get_unaligned_le32((u8 *)__va(req->rel_hpa) + 16),
+ get_unaligned_le32((u8 *)__va(req->rel_hpa) + 20),
+ get_unaligned_le32((u8 *)__va(req->rel_hpa) + 24),
+ get_unaligned_le32((u8 *)__va(req->rel_hpa) + 28));
if (bar0)
pr_info("vgsp-gr: FE readback raw 0x40a500..0x40a50c = %08x %08x %08x %08x (subctx-1 control at 0x40a504)\n",
ioread32(bar0 + 0x0040a500u),
diff --git a/kernel/gsp_phys_gpu.c b/kernel/gsp_phys_gpu.c
index 974100a..f323c6c 100644
--- a/kernel/gsp_phys_gpu.c
+++ b/kernel/gsp_phys_gpu.c
@@ -704,6 +704,28 @@ int gsp_phys_rmcall_gr_qmdwin_value(void)
EXPORT_SYMBOL_GPL(gsp_phys_rmcall_gr_qmdwin_value);
/*
+ * m64 forced module-semaphore release (gsp_phys_rmcall_gr_rel_mod; default 0).
+ * When set, a forwarded GR launch ignores the resolved guest release page and
+ * points QMD release0 at the module window-0 semaphore VA
+ * (GSP_PHYS_RMCALL_VA_SEM), which the host polls at the SEM chunk's host VA.
+ * Discriminant for "engine completed but the shadow release write was lost"
+ * vs "engine never completed": with the module release, a completed QMD is
+ * always observable. Also makes the existing module-release fallback
+ * observable (it previously set no poll source, so it could never complete).
+ */
+static int gsp_phys_rmcall_gr_rel_mod_param;
+module_param_named(gsp_phys_rmcall_gr_rel_mod,
+ gsp_phys_rmcall_gr_rel_mod_param, int, 0644);
+MODULE_PARM_DESC(gsp_phys_rmcall_gr_rel_mod,
+ "Force the forwarded GR QMD release0 to the module semaphore (default 0; 1 = m64 engine-completion discriminant)");
+
+int gsp_phys_rmcall_gr_rel_mod_value(void)
+{
+ return gsp_phys_rmcall_gr_rel_mod_param;
+}
+EXPORT_SYMBOL_GPL(gsp_phys_rmcall_gr_rel_mod_value);
+
+/*
* Ladder VAS ownership selector (gsp_phys_rmcall_vas_shared; default 0).
* The H1 GR promote wall is a direct consequence of the ladder's
* externally-owned FERMI_VASPACE_A: with IS_EXTERNALLY_OWNED the RM treats
diff --git a/kernel/gsp_phys_gpu.h b/kernel/gsp_phys_gpu.h
index 2087e33..84461e8 100644
--- a/kernel/gsp_phys_gpu.h
+++ b/kernel/gsp_phys_gpu.h
@@ -325,6 +325,10 @@ int gsp_phys_rmcall_gr_pcas_two_step_value(void);
*/
int gsp_phys_rmcall_gr_qmdwin_value(void);
+/* m64 discriminant: force the forwarded GR QMD release0 to the module
+ * semaphore so engine completion is always observable (default 0). */
+int gsp_phys_rmcall_gr_rel_mod_value(void);
+
/*
* Ladder VAS ownership selector (gsp_phys_rmcall_vas_shared; default 0).
* 0 = FERMI_VASPACE_A is allocated IS_EXTERNALLY_OWNED (historical ladder