diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-09 09:44:31 -0500 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-09 09:44:31 -0500 |
| commit | 1ad9216aee2f38bfbb6dc29c2b554eced520d7f8 (patch) | |
| tree | 68872aa1af5b25a2fd79b5516df7f9699ea40c7d | |
| parent | 21a2f8b57dbd230bb7f2b5d2522884624d4c4c74 (diff) | |
| download | open-iov-1ad9216aee2f38bfbb6dc29c2b554eced520d7f8.tar.gz open-iov-1ad9216aee2f38bfbb6dc29c2b554eced520d7f8.zip | |
vgsp-sema: scope GR release deferral to the push's own candidate; fan direct-GL completionsHEADmaster
The GL client's direct-GL init push (beef0100, va=0x4000000) decoded its
release (rel=0x4238000 pay=1) but never applied it: svc_fwd_defer_arm() is
global over the cross-pass GR candidate ring, so stale unoffered CUDA/RC
candidates made any later push "defer" its release. The record was then
wiped by the next decode pass (the r824 failure mode) - no sema-sw,
pending or deferred line, and the client's fence never advanced.
Apply the r824 rule already used by the C56F site to the SET_REPORT_SEMAPHORE
and LAUNCH_DMA sites: defer only when the candidate ring entry belongs to
this push (push_va match). A release whose push owns no candidate applies
inline. Also queue svc_rel_apply_906f() releases on a translation miss
instead of dropping them, add a bounded low-VA sema-sw provenance window,
and fan direct-GL semaphore completions (0x4000000..0x4300000) through
every published VAS translation (the general resolver can name a stale
page while the client polls the beef0300 walk page).
Evidence: backups/evidence-20261002-victory/r1656 (beef0100 release decoded,
never applied) and r1657 (sema-sw va=0x4238000 rb_ok=1 after the fix).
| -rw-r--r-- | kernel/gsp_sema_service.c | 62 |
1 files changed, 55 insertions, 7 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 797c4b5..f7a5c7a 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -5809,6 +5809,7 @@ static int svc_sem_write(struct nv_vgpu_device *vgpu, u32 h, u64 va, u32 val) bool verified = false; bool rb_ok = false; static u32 sem_sw_dev_log; /* r619: non-pool device-VA write budget */ + static u32 sem_sw_low_log; /* r1656: low GR release-VA write budget */ /* * Pool semaphores resolve pin -> verified cache -> targeted rm_mem @@ -5892,11 +5893,23 @@ static int svc_sem_write(struct nv_vgpu_device *vgpu, u32 h, u64 va, u32 val) * other windows so a hot loop cannot flood dmesg. */ (va >= 0x120000000ULL && va < 0x120600000ULL && - svc.sem_sw_xg_log < 2048))) { + svc.sem_sw_xg_log < 2048) || + /* + * r1656: the direct-GL GR/GRCE release arena (0x04000000.. + * 0x0fffffff). The GR init push's SET_REPORT_SEMAPHORE + * release (e.g. va=0x4238000 pay=1) lands here, outside every + * window above, so a successful (or failed) write was + * invisible - the "decoded but never applied" class. Bounded + * so a hot release loop cannot flood dmesg. + */ + (va >= SVC_LOW_REL_VA_LO && va < SEMA_VA_LO && + sem_sw_low_log < 512))) { if (va >= 0x79240000000ULL && va < 0x79260000000ULL) svc.sem_sw_log++; else if (va >= 0x120000000ULL && va < 0x120600000ULL) svc.sem_sw_xg_log++; + else if (va >= SVC_LOW_REL_VA_LO && va < SEMA_VA_LO) + sem_sw_low_log++; else sem_sw_dev_log++; pr_info("sema-sw: h=0x%x va=0x%llx pa=0x%llx ap=%d src=%s val=0x%x rc=%d rb_ok=%d back=0x%x pool=%d\n", @@ -5909,6 +5922,16 @@ static int svc_sem_write(struct nv_vgpu_device *vgpu, u32 h, u64 va, u32 val) svc_pool_boot_fanout(vgpu, h, va, val); svc_pool_write_all_vas(vgpu, h, va, val); svc_pool_tracker_apply(vgpu, h, va, val); + } else if (va >= 0x4000000ULL && va < 0x4300000ULL) { + /* + * r1657: direct-GL kernel-VAS semaphores. The + * general resolver can name a stale page for these + * (r1657 beef0100 rel 0x4238000 landed at the + * fallback PA while the client polls the beef0300 + * walk page). Fan the forward-only completion out + * through every published VAS translation too. + */ + svc_pool_write_all_vas(vgpu, h, va, val); } return 0; } @@ -11333,16 +11356,28 @@ static void svc_gr_bridge_fallback(struct nv_vgpu_device *vgpu) * Both still require the guest-memory path that makes any hardware * submission possible. Service-thread only, like the captures. */ -static bool svc_fwd_defer_arm(void) +static bool svc_fwd_defer_arm(u64 push_va) { if (!gsp_phys_guest_mem_enabled()) return false; if (gsp_phys_gr_forward_enabled()) { u32 ri; + /* + * r1656: the GR candidate ring survives across decode passes, + * so a candidate captured for ANOTHER launch must not withhold + * this push's release. r824 added this ownership test to the + * C56F release site only; the SET_REPORT_SEMAPHORE and + * LAUNCH_DMA sites kept the global test, and an unrelated + * lingering candidate parked a GR init release that was then + * discarded at the next pass reset (decoded, never applied). + * Only the launch's own push may defer; anything else applies + * inline. + */ for (ri = 0; ri < SVC_GR_CAND_RING; ri++) if (svc_gr_cand_ring[ri].valid && - !svc_gr_cand_ring[ri].offered) + !svc_gr_cand_ring[ri].offered && + svc_gr_cand_ring[ri].push_va == push_va) return true; } return svc_fwd_cand.valid && @@ -15202,7 +15237,20 @@ static bool svc_rel_apply_906f(struct nv_vgpu_device *vgpu, op == HOST_SEM_OP_REDUCTION); return false; } - if (!svc_sem_read(vgpu, va, &cur) && payload > cur) { + if (svc_sem_read(vgpu, va, &cur)) { + /* + * r1656: a decoded release whose target page has no + * translation yet used to be dropped here with no write, no + * pending entry and no log - unlike svc_rel_apply_reportsem() + * and svc_rel_apply_launch(), which both queue the miss. Queue + * it so svc_apply_pending() retries once a pin or the client's + * VAS walk knows the page; a reduction stays additive. + */ + svc_pending_add(va, payload, + (op == HOST_SEM_OP_REDUCTION) ? 1u : 0u); + return false; + } + if (payload > cur) { svc.pushes_pending++; cur = (op == HOST_SEM_OP_REDUCTION) ? cur + payload : payload; if (!svc_sem_write(vgpu, ch->h_object, va, cur)) { @@ -20418,7 +20466,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, * forwarding has nothing to wait * for and applies inline. */ - if (svc_fwd_defer_arm() && + if (svc_fwd_defer_arm(push_va) && svc_fwd_cand_owns_push(push_va) && !svc.op_tr_pending) { svc_opdef_drop(vgpu, ch, @@ -20595,7 +20643,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, * own it, and then it is recorded * instead of applied. */ - if (svc_fwd_defer_arm()) { + if (svc_fwd_defer_arm(push_va)) { svc_opdef_drop(vgpu, ch, entry_idx); if (svc_fwd_rel_n < SVC_FWD_REL_MAX) { @@ -22143,7 +22191,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, or.payload = st.sem_payload; or.entry_idx = entry_idx; or.dma = dma; - if (svc_fwd_defer_arm()) { + if (svc_fwd_defer_arm(push_va)) { svc_opdef_drop(vgpu, ch, entry_idx); if (svc_fwd_rel_n < SVC_FWD_REL_MAX) { |
