diff options
Diffstat (limited to 'kernel/gsp_phys_booter.c')
| -rw-r--r-- | kernel/gsp_phys_booter.c | 70 |
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; |
