summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-11 22:34:10 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-11 22:34:10 -0400
commitcb6cfc0e2c85e24a3151d70df2743701fc1b3540 (patch)
treeef347a31e3af6e10d9983686fa4f8d1fd6b08d2a /kernel
parenta7874aa9bebcdb469fd5f0a9beb4b1b18315d1a2 (diff)
downloadopen-iov-cb6cfc0e2c85e24a3151d70df2743701fc1b3540.tar.gz
open-iov-cb6cfc0e2c85e24a3151d70df2743701fc1b3540.zip
vgsp-gr: one bounded re-arm of a stalled forwarded launch (context save/unload lottery)
r90 evidence: the 3rd session's forwarded launch entered SKED (CWD VALID) and was then saved/unloaded by the FECS before dispatch; qmd_rel stayed at 5/6, GP_GET froze, and every later launch on the boot was never fetched either. The service owns no repair path, so the channel stayed dead until reboot. On the first poll timeout, re-issue the two GPFIFO_SCHEDULE controls the stage-4 sequence used (channel-level 0xa06f0103 + TSG-level 0xa06c0101, both proven accepted) and re-ring the work-submit doorbell, then poll one more full window before the postmortem. No BIND, no PROMOTE (m76-m81 proved the explicit PREEMPT/tail variants stop the QMD enqueuing).
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 72b500a..e2c2989 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -16452,6 +16452,49 @@ static int gsp_phys_rmcall_gr_data_map(void __iomem *bar0, u64 va, u64 hpa,
* queue (epoch-gated) into out->fault. Every refusal moves the GR counters
* and returns an errno the sema service falls back on.
*/
+/*
+ * m142: re-arm a stalled forwarded launch. The engine dispatch path is
+ * nondeterministic: the QMD can enter SKED and then be saved/unloaded by the
+ * FECS before it dispatches, after which the channel is never fetched again
+ * (r90: qmd_rel stuck at 5/6, GP_GET frozen, every later launch on the boot
+ * also unfetched). The schedule state set once at stage 4 is the only re-arm
+ * lever the service owns: re-issue the same channel-level and TSG-level
+ * GPFIFO_SCHEDULE controls the stage-4 sequence used (both proven accepted)
+ * and re-ring the work-submit doorbell so a PBDMA that stopped polling is
+ * prompted again. No BIND, no PROMOTE: m76-m81 proved the explicit
+ * PREEMPT/tail variants stop the QMD from enqueuing at all.
+ */
+static int gsp_phys_rmcall_gr_resched_locked(void __iomem *bar0)
+{
+ u8 sched_params[2] = { 1, 0 };
+ u32 rpc_result = 0, status = 0;
+ u32 runlist_id, ch_id, doorbell;
+ int ret;
+
+ ret = gsp_phys_rmcall_control(bar0, boot_stage.rmcall_channel,
+ GSP_PHYS_RMCALL_CTRL_GPFIFO_SCHEDULE,
+ sched_params, sizeof(sched_params), 16,
+ NULL, 0, &rpc_result, &status,
+ "GR rearm GPFIFO_SCHEDULE");
+ if (ret)
+ return ret;
+ rpc_result = 0;
+ status = 0;
+ ret = gsp_phys_rmcall_control(bar0, boot_stage.rmcall_tsg,
+ GSP_PHYS_RMCALL_CTRL_TSG_GPFIFO_SCHEDULE,
+ sched_params, sizeof(sched_params), 16,
+ NULL, 0, &rpc_result, &status,
+ "GR rearm TSG_GPFIFO_SCHEDULE");
+ if (ret)
+ return ret;
+ runlist_id = (boot_stage.rmcall_token >> 16) & 0x7fu;
+ ch_id = boot_stage.rmcall_token & 0xfffu;
+ doorbell = ((runlist_id << 16) & 0x7f00000u) | (ch_id & 0xfffu);
+ wmb();
+ writel(doorbell, bar0 + GSP_PHYS_RMCALL_DOORBELL_OFF);
+ return 0;
+}
+
int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
struct gsp_phys_backend_copy_result *out)
{
@@ -16502,6 +16545,7 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
bool qmd_win_diag = false;
bool qmdwin_on = false;
char qmdwin_note[32] = "";
+ bool rearmed = false;
int ret = 0;
if (out)
@@ -17460,6 +17504,32 @@ gr_page_unmapped:
pr_err("vgsp-gr: GR LAUNCH FAILED: timeout after %u ms (qmd_rel=0x%08x want=0x%08x ch_rel=0x%08x want=0x%08x) h=0x%x push=0x%llx\n",
GSP_PHYS_RMCALL_GR_POLL_MS, w0, want_qmd, w1,
want_ch, req->h_object, req->push_va);
+ /*
+ * m142: one bounded re-arm before declaring the launch
+ * dead. Re-issue the stage-4 schedule controls and re-ring
+ * the doorbell, then poll again; if the channel was merely
+ * de-scheduled (context save/unload lottery) this revives
+ * it. A second timeout falls through to the postmortem.
+ */
+ if (!rearmed) {
+ int rr;
+
+ rearmed = true;
+ mutex_lock(&gsp_phys_rm_lock);
+ rr = gsp_phys_rmcall_gr_resched_locked(bar0);
+ mutex_unlock(&gsp_phys_rm_lock);
+ if (!rr) {
+ pr_info("vgsp-gr: rearm after timeout: schedule re-issued + doorbell re-rung; re-polling %u ms\n",
+ GSP_PHYS_RMCALL_GR_POLL_MS);
+ deadline = jiffies +
+ msecs_to_jiffies(
+ GSP_PHYS_RMCALL_GR_POLL_MS);
+ grpoll_n = 0;
+ continue;
+ }
+ pr_info("vgsp-gr: rearm after timeout failed rc=%d\n",
+ rr);
+ }
if (gsp_phys_gr_fault_active()) {
struct gsp_phys_fault_info fi;
u32 fep = 0;