From 6b090f70816f60a1a98fcf5889a3275177e8c132 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Wed, 14 Oct 2026 13:40:54 -0400 Subject: vgsp-gr: bounded fresh-entry retry for a forwarded launch whose QMD did not run A green forwarded launch completes in ~170-195 ms, but an intermittent subset times out with qmd_rel stuck at 5 (cold context save/unload, or an entry the PBDMA never fetched). The existing recovery only replays the schedule verbs, which cannot help once the entry was fetched or never latched, so the client fell back to the software release and read stale/zero results. On a timeout, after the schedule re-arm, re-publish a FRESH ring entry with the same PB/QMD content and re-issue schedule+doorbell, up to GSP_PHYS_RMCALL_GR_ATTEMPTS (3) with a GSP_PHYS_RMCALL_GR_RETRY_MS (2000 ms) poll. Safe against double execution: the timeout path never copies the result out to the guest, so a timed-out attempt did not reach the client - only the eventually-successful attempt is visible. New counter gsp_phys_gr_retries and a 'retry N/M fresh ring entry' log line. --- kernel/gsp_phys_booter.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'kernel/gsp_phys_booter.c') 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; -- cgit v1.2.3