diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-15 02:33:03 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-15 02:33:03 -0400 |
| commit | 7e36e2909280414916c821e29e00b341750c8a8f (patch) | |
| tree | 596c5932b8399e9838616aa211148d8564966273 /kernel | |
| parent | 4806384848c2903e921dfdefdc8096854e40480f (diff) | |
| download | open-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.c | 196 |
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, |
