summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-15 02:33:03 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-15 02:33:03 -0400
commit7e36e2909280414916c821e29e00b341750c8a8f (patch)
tree596c5932b8399e9838616aa211148d8564966273 /kernel
parent4806384848c2903e921dfdefdc8096854e40480f (diff)
downloadopen-iov-7e36e2909280414916c821e29e00b341750c8a8f.tar.gz
open-iov-7e36e2909280414916c821e29e00b341750c8a8f.zip
vgsp-gr: retirement wait - whole-window footprint with adaptive exits
Footprint-by-inference (max-reloc contiguous run, launch-page exclusion) failed twice: the fill's candidate list ends with the launch's own bank/ param pages, so the inferred output run was 3-4 pages (r150/r151: '0/3 pages changed after 72 ms (no writes)') and the wait exited before any real output landed. Replace with a whole-window count over every resolved data page plus cheap adaptive exits: - all pages changed -> done (one poll in the normal case), - partial count stable for 3 polls -> stores settled, - no change for 600 ms -> no output for this launch, - hard cap 1.5 s. No inference, no exclusion list, bounded cost.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c196
1 files changed, 67 insertions, 129 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index bc312b0..bd70b7d 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -16601,151 +16601,89 @@ static inline u64 gsp_phys_gr_fnv1a64(const u8 *p, size_t len)
}
/*
- * m151: output-footprint retirement wait. qmd_rel is a schedule/fetch ack
- * (the front end latched and fetched the QMD), not a data-path retirement:
- * the SM's stores into the bounce pages can still be in flight when the ack
- * lands. Copying out - and the next launch's copy-in - before those stores
- * land loses them: the guest observes zeros for a completed launch, or
+ * m151: output retirement wait. qmd_rel is a schedule/fetch ack (the front
+ * end latched and fetched the QMD), not a data-path retirement: the SM's
+ * stores into the bounce pages can still be in flight when the ack lands.
+ * Copying out - and the next launch's copy-in - before those stores land
+ * loses them: the guest observes zeros for a completed launch, or
* stale/mixed content when the next copy-in races the previous engine's
- * write tail. Wait (bounded at 300 x 5 ms) until every page of the output
- * footprint has changed from its copy-in checksum. noinline so this
- * rarely-taken wait does not grow the submit frame, which is already near
- * the warning bound.
+ * write tail.
+ *
+ * The wait covers EVERY resolved data page (footprint-by-inference was
+ * tried twice and is unreliable: the fill's candidate list ends with the
+ * launch's own bank/param pages, so the max-reloc run is 3-4 pages, not
+ * the output operand). Adaptive exits make a whole-window count cheap:
+ * - all resolved pages changed -> done (normal case, one poll)
+ * - changed>0 and stable for 3 polls -> stores settled (masked or
+ * repeated-identical kernels)
+ * - no writes at all for 600 ms -> no output for this launch
+ * - hard cap 1.5 s -> genuinely late remainder
+ * noinline so this rarely-taken wait does not grow the submit frame, which
+ * is already near the warning bound.
*/
static noinline void
gsp_phys_gr_output_retire_wait(const struct gsp_phys_gr_submit *req,
const u32 *csum_in)
{
- u64 out_base = 0;
- u32 out_pages = 0, di;
+ u32 checked[GSP_PHYS_RMCALL_GR_MAIL_SLOT];
+ u32 n_all = 0, di, iter;
+ u32 changed = 0, prev = 0xffffffffu;
+ const char *why = " (TIMEOUT)";
+ unsigned long wait_start = jiffies;
- /*
- * The output footprint is the contiguous descending reloc run from
- * the highest reloc_va that belongs to a kernel OPERAND. The fill
- * also relocates the launch's own param/bank pages (they appear as
- * high-VA candidates in the push), and those would otherwise make
- * out_base the top of the window and out_pages the whole budget -
- * the r147 first cut waited the full 1.5 s on every launch because
- * of it. Exclude any data entry whose guest VA is one of the
- * forwarded launch pages (qmd_word pages; 0xffffffff marks the
- * non-QMD forwarded pages).
- */
+ if (!req->n_data)
+ return;
for (di = 0; di < req->n_data; di++) {
- u32 pj;
- bool launch_page = false;
+ u32 bi = (u32)((req->data[di].reloc_va -
+ GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >> 12);
+ u32 k;
+ bool dup = false;
- /*
- * Exclude EVERY forwarded launch page - including the
- * 0xffffffff (non-QMD) ones (pushbuffer/indirect/bank pages
- * the fill also relocates as high-VA candidates). r150
- * excluded only the QMD pages and out_base landed on the
- * 0x1d9000 bank page group: out_pages=3, the wait exited
- * after 72 ms and the late-write capture was lost.
- */
- for (pj = 0; pj < req->n_pages; pj++) {
- if (req->pages[pj].guest_va == req->data[di].va) {
- launch_page = true;
- break;
- }
- }
- if (launch_page)
+ if (bi >= GSP_PHYS_RMCALL_GR_MAIL_SLOT)
continue;
- if (req->data[di].reloc_va > out_base)
- out_base = req->data[di].reloc_va;
- }
- if (out_base) {
- for (;;) {
- u64 want = out_base -
- (u64)out_pages * GSP_PHYS_PAGE_SIZE;
- u32 k;
- bool hit = false;
-
- for (k = 0; k < req->n_data; k++) {
- if (req->data[k].reloc_va != want)
- continue;
- /* launch pages were excluded from out_base */
- {
- u32 pj;
- bool lp = false;
-
- for (pj = 0; pj < req->n_pages; pj++) {
- if (req->pages[pj].guest_va ==
- req->data[k].va) {
- lp = true;
- break;
- }
- }
- if (lp)
- continue;
- }
- hit = true;
+ for (k = 0; k < n_all; k++)
+ if (checked[k] == bi) {
+ dup = true;
break;
}
- if (!hit ||
- out_pages >= GSP_PHYS_RMCALL_GR_MAIL_SLOT)
- break;
- out_pages++;
- }
+ if (!dup)
+ checked[n_all++] = bi;
}
- if (!out_pages)
- out_pages = 1u;
- else if (out_pages > GSP_PHYS_RMCALL_GR_MAIL_SLOT)
- out_pages = GSP_PHYS_RMCALL_GR_MAIL_SLOT;
- if (out_pages >= 2u) {
- unsigned long wait_start = jiffies;
- u32 changed = 0, prev = 0xffffffffu, iter;
- const char *why = " (TIMEOUT)";
-
- for (iter = 0; iter < 300u; iter++) {
- u32 j;
-
- changed = 0;
- for (j = 0; j < out_pages; j++) {
- u64 va = out_base -
- (u64)j * GSP_PHYS_PAGE_SIZE;
- u32 bi = (u32)((va -
- GSP_PHYS_RMCALL_GR_BOUNCE_VA0) >> 12);
- const u8 *src;
- u32 ci, csum = 0;
+ if (!n_all)
+ return;
+ for (iter = 0; iter < 300u; iter++) {
+ u32 j;
- if (bi >= GSP_PHYS_RMCALL_GR_MAIL_SLOT)
- continue;
- src = gsp_phys_chunk_page_va(
- &boot_stage.rmcall_gr_bounce, bi);
- for (ci = 0; ci < GSP_PHYS_PAGE_SIZE; ci += 4)
- csum += get_unaligned_le32(src + ci);
- if (csum != csum_in[bi])
- changed++;
- }
- if (changed >= out_pages) {
- why = "";
- break;
- }
- /*
- * Adaptive exits: no write at all after 60 ms means the
- * engine either rewrote identical bytes (a repeated
- * benchmark launch) or produced no output for this
- * footprint; a partial count that stops growing for
- * three polls means the stores have settled (masked /
- * partial-output kernels). Both avoid paying the full
- * 1.5 s on every launch while still catching genuinely
- * late writes.
- */
- if (iter >= 12u && changed == 0) {
- why = " (no writes)";
- break;
- }
- if (changed > 0 && changed == prev && iter >= 24u) {
- why = " (settled)";
- break;
- }
- prev = changed;
- usleep_range(4000, 6000);
+ changed = 0;
+ for (j = 0; j < n_all; j++) {
+ const u8 *src = gsp_phys_chunk_page_va(
+ &boot_stage.rmcall_gr_bounce, checked[j]);
+ u32 ci, csum = 0;
+
+ if (!src)
+ continue;
+ for (ci = 0; ci < GSP_PHYS_PAGE_SIZE; ci += 4)
+ csum += get_unaligned_le32(src + ci);
+ if (csum != csum_in[checked[j]])
+ changed++;
+ }
+ if (changed >= n_all) {
+ why = "";
+ break;
+ }
+ if (changed > 0 && changed == prev && iter >= 3u) {
+ why = " (settled)";
+ break;
+ }
+ if (changed == 0 && iter >= 120u) {
+ why = " (no writes)";
+ break;
}
- pr_info("vgsp-gr: output retirement wait: %u/%u pages changed after %u ms%s\n",
- changed, out_pages,
- jiffies_to_msecs(jiffies - wait_start), why);
+ prev = changed;
+ usleep_range(4000, 6000);
}
+ pr_info("vgsp-gr: output retirement wait: %u/%u pages changed after %u ms%s\n",
+ changed, n_all, jiffies_to_msecs(jiffies - wait_start), why);
}
int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,