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.c113
1 files changed, 110 insertions, 3 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 0f7e91c..009eb4f 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -17186,6 +17186,7 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
int qmd_win_ret = 0;
bool qmd_win_diag = false;
bool qmdwin_on = false;
+ u32 qw_bank = 0;
char qmdwin_note[32] = "";
bool rearmed = false;
u32 attempts = 0;
@@ -17818,7 +17819,7 @@ gr_page_unmapped:
NULL;
if (boot_stage.rmcall_gr_qmdwin_va && qw) {
- u32 qw_bank = (epoch & 1u) %
+ qw_bank = (epoch & 1u) %
GSP_PHYS_RMCALL_GR_QMDWIN_SLOTS;
qmdwin_on = true;
@@ -18643,6 +18644,69 @@ gr_page_unmapped:
break;
}
}
+ /*
+ * m160 (fresh-ack + fresh-deposit retry): the m153
+ * retry re-published the same PB and then polled
+ * the release words WITHOUT clearing them - the
+ * previous attempt's ack (the identical payload)
+ * satisfied the poll instantly, so every retry
+ * burned only the retirement wait and concluded
+ * "engine wrote 0" without ever having waited for
+ * the engine to consume the re-published entry
+ * (r162: 3 dud retries, ~870 ms each, then
+ * accepted). Clear the guest release words (and
+ * the module semaphore when the QMD won't reach a
+ * guest page) so the poll below waits for a FRESH
+ * ack, and move the inline-QMD deposit to the
+ * other qmdwin bank (fresh epoch) and rebuild the
+ * method block for it, so the engine cannot have
+ * a cached fetch line or a stale deposit for the
+ * retry's entry. The mechanical sequence is
+ * exactly the one r162's ok=7 saga used when it
+ * recovered the no-execute launch (fresh ring
+ * entry + resched + fresh deposit).
+ */
+ if (qmd_rel_hpa)
+ WRITE_ONCE(*(u32 *)((u8 *)__va(qmd_rel_hpa) +
+ qmd_rel_off), 0);
+ if (ch_rel_hpa)
+ WRITE_ONCE(*(u32 *)((u8 *)__va(ch_rel_hpa) +
+ ch_rel_off), 0);
+ WRITE_ONCE(*(u32 *)sem_va, 0);
+ WRITE_ONCE(*(u32 *)(sem_va + 4), 0);
+ wmb();
+ if (qmdwin_on &&
+ boot_stage.rmcall_gr_qmdwin.pages) {
+ epoch = ++boot_stage.rmcall_gr_submit_epoch;
+ if (!epoch)
+ epoch = ++boot_stage.rmcall_gr_submit_epoch;
+ qw_bank = (epoch & 1u) %
+ GSP_PHYS_RMCALL_GR_QMDWIN_SLOTS;
+ qmd_dst = boot_stage.rmcall_gr_qmdwin_va +
+ (u64)qw_bank *
+ GSP_PHYS_PAGE_SIZE;
+ qmd_dst_mem = gsp_phys_chunk_page_va(
+ &boot_stage.rmcall_gr_qmdwin,
+ qw_bank);
+ if (qmd_dst_mem) {
+ memcpy(qmd_dst_mem, qmd,
+ GSP_PHYS_GR_QMD_WORDS * 4);
+ put_unaligned_le32(
+ GSP_PHYS_GR_QMD_SENTINEL,
+ qmd_dst_mem +
+ GSP_PHYS_GR_QMD_SENTINEL_WORD * 4);
+ }
+ words = gsp_phys_rmcall_build_gr_launch(
+ methods, req, qmd, qmd_dst,
+ ch_sem_va, want_ch);
+ memcpy(gsp_phys_chunk_page_va(pb, 0),
+ methods, words * 4);
+ pr_info("vgsp-gr: outcome retry %u: release words zeroed + fresh qmdwin bank %u dest 0x%llx + PB rebuilt\n",
+ attempts, qw_bank, qmd_dst);
+ } else {
+ pr_info("vgsp-gr: outcome retry %u: release words zeroed (qmdwin off)\n",
+ attempts);
+ }
gsp_phys_gr_fill_bounce(req, bounce_csum_in);
mutex_lock(&gsp_phys_rm_lock);
ret = gsp_phys_rmcall_publish_locked(
@@ -18661,8 +18725,10 @@ gr_page_unmapped:
{
unsigned long dl = jiffies +
msecs_to_jiffies(
- GSP_PHYS_RMCALL_GR_RETRY_MS);
+ GSP_PHYS_RMCALL_GR_POLL_MS);
+ unsigned long ack_start = jiffies;
u32 rw0 = 0, rw1 = 0;
+ bool acked = false;
for (;;) {
if (qmd_rel_hpa)
@@ -18683,18 +18749,59 @@ gr_page_unmapped:
*(u32 *)(sem_va + 4));
if ((!qmd_rel ||
rw0 == want_qmd) &&
- rw1 == want_ch)
+ rw1 == want_ch) {
+ acked = true;
break;
+ }
if (time_after_eq(jiffies, dl))
break;
msleep(GSP_PHYS_RMCALL_POLL_MS);
}
+ pr_info("vgsp-gr: outcome retry %u: fresh ack %s (qmd_rel=0x%08x want=0x%08x ch_rel=0x%08x after %u ms)\n",
+ attempts,
+ acked ? "OK" : "TIMEOUT",
+ rw0, want_qmd, rw1,
+ jiffies_to_msecs(jiffies -
+ ack_start));
}
wrote = gsp_phys_gr_output_retire_wait(
req, bounce_csum_in);
pr_info("vgsp-gr: outcome retry %u done: engine wrote %u page(s)\n",
attempts, wrote);
}
+ /*
+ * m160: if every fresh-ack retry still produced no
+ * engine writes, the release words may be left zeroed
+ * from the last retry. Restore the expected payloads so
+ * the guest client observes its completion and proceeds
+ * to its own result check (a genuinely lost launch then
+ * surfaces as the client's own FAIL, never as a hang).
+ */
+ if (wrote == 0) {
+ bool restored = false;
+
+ if (qmd_rel_hpa) {
+ u8 *rp = (u8 *)__va(qmd_rel_hpa) +
+ qmd_rel_off;
+
+ if (READ_ONCE(*(u32 *)rp) != want_qmd) {
+ WRITE_ONCE(*(u32 *)rp, want_qmd);
+ restored = true;
+ }
+ }
+ if (ch_rel_hpa) {
+ u8 *rp = (u8 *)__va(ch_rel_hpa) +
+ ch_rel_off;
+
+ if (READ_ONCE(*(u32 *)rp) != want_ch) {
+ WRITE_ONCE(*(u32 *)rp, want_ch);
+ restored = true;
+ }
+ }
+ if (restored)
+ pr_info("vgsp-gr: no-write accept: release words restored (qmd=0x%08x ch=0x%08x); client's own check decides\n",
+ want_qmd, want_ch);
+ }
}
}
/*