summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-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;