summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 879fca4..0c3e829 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -1422,6 +1422,20 @@ enum gsp_phys_rmcall_buf {
* generous and progress is logged every ~500 ms.
*/
#define GSP_PHYS_RMCALL_GR_POLL_MS 5000u
+/*
+ * Bounded retry of a forwarded GR launch whose QMD did not run. A green
+ * launch completes in ~170-195 ms; when the engine drops it (cold context
+ * save/unload, or an entry the PBDMA never fetched) `qmd_rel` never reaches
+ * the wanted value and the client would fall back to the software release
+ * and read stale/zero results. Because the timeout path never copies the
+ * result out to the guest, a launch that timed out did not reach the
+ * client: re-publishing a FRESH ring entry (same PB/QMD) and re-issuing the
+ * schedule+doorbell gives the front-end another chance and the guest still
+ * sees only the success path. Bounded so the service thread is never held
+ * past the existing hold budget.
+ */
+#define GSP_PHYS_RMCALL_GR_RETRY_MS 2000u
+#define GSP_PHYS_RMCALL_GR_ATTEMPTS 3u
/* P6a guest-memory CE copies: same bounded poll cap as the P5 shadow path. */
#define GSP_PHYS_RMCALL_GUEST_POLL_MS 200u
@@ -15751,6 +15765,7 @@ static u64 gsp_phys_gr_submitted;
static u64 gsp_phys_gr_ok;
static u64 gsp_phys_gr_refused;
static u64 gsp_phys_gr_timed_out;
+static u64 gsp_phys_gr_retries; /* fresh-entry launch retries published */
static u64 gsp_phys_gr_pool_exhausted;
/* m86: program-page override blob (see gsp-phys-gr-override). */
static u8 gsp_phys_gr_override[GSP_PHYS_PAGE_SIZE];
@@ -16559,6 +16574,7 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
bool qmdwin_on = false;
char qmdwin_note[32] = "";
bool rearmed = false;
+ u32 attempts = 0;
int ret = 0;
if (out)
@@ -17594,6 +17610,45 @@ gr_page_unmapped:
pr_info("vgsp-gr: rearm after timeout failed rc=%d\n",
rr);
}
+ /*
+ * The re-arm above only replays the schedule verbs; if the
+ * entry was already fetched or the front-end never latched
+ * it, that cannot make the QMD run. Re-publish a FRESH ring
+ * entry (same PB content and QMD) with a re-issued schedule
+ * + doorbell, bounded. The timeout path never copied the
+ * result out to the guest, so a timed-out attempt did not
+ * reach the client; the guest therefore still sees only the
+ * successful attempt.
+ */
+ if (attempts < GSP_PHYS_RMCALL_GR_ATTEMPTS) {
+ int pr_ret;
+
+ attempts++;
+ mutex_lock(&gsp_phys_rm_lock);
+ pr_ret = gsp_phys_rmcall_publish_locked(
+ bar0, boot_stage.rmcall_va_pb, words,
+ &sub);
+ if (!pr_ret)
+ pr_ret = gsp_phys_rmcall_gr_resched_locked(
+ bar0);
+ mutex_unlock(&gsp_phys_rm_lock);
+ if (!pr_ret) {
+ gsp_phys_gr_retries++;
+ pr_info("vgsp-gr: retry %u/%u: fresh ring entry slot=%u published + rescheduled; re-polling %u ms\n",
+ attempts,
+ GSP_PHYS_RMCALL_GR_ATTEMPTS,
+ sub.slot,
+ GSP_PHYS_RMCALL_GR_RETRY_MS);
+ deadline = jiffies +
+ msecs_to_jiffies(
+ GSP_PHYS_RMCALL_GR_RETRY_MS);
+ rearmed = false;
+ grpoll_n = 0;
+ continue;
+ }
+ pr_info("vgsp-gr: retry %u publish failed rc=%d\n",
+ attempts, pr_ret);
+ }
if (gsp_phys_gr_fault_active()) {
struct gsp_phys_fault_info fi;
u32 fep = 0;