summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-09 09:44:31 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-09 09:44:31 -0500
commit1ad9216aee2f38bfbb6dc29c2b554eced520d7f8 (patch)
tree68872aa1af5b25a2fd79b5516df7f9699ea40c7d
parent21a2f8b57dbd230bb7f2b5d2522884624d4c4c74 (diff)
downloadopen-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.c62
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) {