From 1595efde3d9a8fc08dc892fd88b48dbb84715095 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Sun, 18 Oct 2026 00:04:28 -0400 Subject: vgsp: m179 GR no-write robustness - dedicated re-execution budget + specific zero-write test + loud classified accept The r200-r202 memcpy_roundtrip/multikernel all-wrong class: a forwarded GR launch retires with zero tracked engine writes (NOWRITE, qmd_rel satisfied), the m153 outcome-retry loop either never ran (it shared the timeout ladder's attempt counter, which the fast re-arm / fresh entries had already consumed) or exhausted, and the accept path silently restored the release words, handing the client an all-wrong output with a fabricated completion. Changes (kernel/gsp_phys_booter.c, gsp_phys_gpu.c, gsp_phys_gpu.h): 1. gsp_phys_gr_nowrite_retries (default 3, clamped [0,4]): the no-write re-execution loop now has a DEDICATED budget, independent of the timeout ladder's attempts. Each retry keeps the existing backoff mechanics (zero release words, fresh qmdwin/win0 bank, refill bounce, rebuild PB, re-publish + resched, fresh-ack poll, fetch witness, retire wait). Worst case stays within the 8-entry GPFIFO ring (initial + fast re-arm + 2 fresh entries + 3 retries = 7 publishes). 2. Specific zero-write test: gsp_phys_gr_output_retire_wait() now reports n_tracked (the number of data entries that resolve to a bounce page); the no-write retry/accept path only triggers when n_tracked > 0, so a launch whose data entries resolve nothing can no longer false-positive as a lost launch. 3. The accept (last resort after the budget) is now LOUD (pr_warn) and classified by the QMD fetch sentinel: NOWRITE-CONFIRMED = deposit never reached the engine (sweep/hold-faked-ack class); NOWRITE-AMBIGUOUS = engine consumed the deposit, zero tracked writes may be a legitimately read-only kernel. It also runs when the retry master gate is off, so a zero-write outcome is never silent. 4. Ordering: explicit wmb() after the retry's fresh qmdwin deposit (the first-attempt path and the publish tail already carry the barriers; dma_wmb before GP_PUT advance + wmb before the doorbell in gsp_phys_rmcall_publish_locked) - deposit->kick order is now explicit on both paths. 5. Frame bound: the ~370-byte struct gsp_phys_fault_info moved to static scratch (the function's documented single-inflight contract, same as methods[]/qmd[]) with a per-submission memset; this clears the pre-existing >1024-byte frame warning in the submit function instead of growing it. Fast re-arm (gsp_phys_gr_retry_fast) and the timeout ladder are untouched. Build: make kernel -j - green, vgsp.ko; no warnings in touched code. --- kernel/gsp_phys_gpu.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'kernel/gsp_phys_gpu.c') diff --git a/kernel/gsp_phys_gpu.c b/kernel/gsp_phys_gpu.c index 95bd627..81c68b4 100644 --- a/kernel/gsp_phys_gpu.c +++ b/kernel/gsp_phys_gpu.c @@ -1020,6 +1020,38 @@ unsigned int gsp_phys_gr_first_poll_ms_value(void) } EXPORT_SYMBOL_GPL(gsp_phys_gr_first_poll_ms_value); +/* + * m179 no-write retry budget (gsp_phys_gr_nowrite_retries; default 3, clamped + * to [0, 4]). The m153 outcome retry loop re-executes a data-bearing launch + * whose retirement wait saw zero engine writes; it shared the timeout ladder's + * attempt counter, so a launch that had already spent attempts on the ladder + * (fast re-arm + fresh ring entries) reached the accept path with NO + * re-execution at all - the r200/r201/r202 memcpy_roundtrip / multikernel + * class (a lost launch silently accepted, client output all wrong). This + * budget is dedicated to the no-write loop and independent of the ladder; it + * is read once per submission. 0 keeps the accept-without-retry behavior + * (still logged loudly). The clamp keeps the worst-case host publishes per + * launch (initial + fast re-arm + 2 fresh entries + budget) within the + * 8-entry GPFIFO ring. + */ +static int gsp_phys_gr_nowrite_retries_param = 3; +module_param_named(gsp_phys_gr_nowrite_retries, + gsp_phys_gr_nowrite_retries_param, int, 0644); +MODULE_PARM_DESC(gsp_phys_gr_nowrite_retries, + "Dedicated re-execution budget for a data-bearing GR launch that wrote nothing tracked, clamped [0,4] (default 3)"); + +int gsp_phys_gr_nowrite_retries_value(void) +{ + int v = gsp_phys_gr_nowrite_retries_param; + + if (v < 0) + v = 0; + if (v > 4) + v = 4; + return v; +} +EXPORT_SYMBOL_GPL(gsp_phys_gr_nowrite_retries_value); + /* * m69 window-0 shadow pool (gsp_phys_rmcall_gr_shadow_win0; default 0). When * set, the forwarded GR launch copies the QMD's program/param pages into the -- cgit v1.2.3