summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-18 06:36:08 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-18 06:37:12 -0400
commit7cd528ad8614a1e623bea598711c276a925b9f57 (patch)
tree3a383e863c9fec440b2d6dc506a6becb6f51587b /kernel/gsp_sema_service.c
parente99040b9ca2acc10a9d4b57fe45626331e203a7c (diff)
downloadopen-iov-7cd528ad8614a1e623bea598711c276a925b9f57.tar.gz
open-iov-7cd528ad8614a1e623bea598711c276a925b9f57.zip
vgsp: GR fill hold - self-enforcing bound at decision point; benign-unresolvable class undecidable (bounded, not bypassed)
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c77
1 files changed, 66 insertions, 11 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 6286d38..3a955df 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -13422,10 +13422,14 @@ static bool svc_fwd_hold_poll(struct nv_vgpu_device *vgpu,
ch->last_get = (idx + 1) % ch->gpfifo_entries;
ch->rescue_fail = 0;
ch->defer_since = 0;
- /* GRFIX FIX1b: this entry is consumed; its per-launch absolute-bound
- * record resets so a later launch (slot/VA reuse) arms a fresh one. */
- ch->gr_hold_dead_va = 0;
- ch->gr_hold_exp_logged = false;
+ /*
+ * GRFIX FIX1c (r214): do NOT reset the per-launch bound record
+ * here. This consume can belong to a different entry than the held
+ * launch, and resetting on every consume re-armed the bound before
+ * it could pass (r214: 420 re-holds, GRFILL-EXPIRED=0 over 220 s).
+ * The record is keyed by the launch push VA; it resets only on
+ * channel (re)registration or the session diag reset.
+ */
ch->submissions++;
svc.gpfifo_entries_done++;
if (ch->engine_type && ch->expected_sem_payload)
@@ -14372,7 +14376,8 @@ static bool svc_gr_hold_bound_expired(struct svc_channel *ch, u64 launch_va)
return time_after_eq(jiffies, ch->gr_hold_deadline);
}
-static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
+static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
+ struct svc_channel *ch)
{
u64 wins[16];
bool is_arg[16]; /* m150: candidate came from the argument scan */
@@ -14412,6 +14417,8 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
* (gsp_phys_gr_hold_max_ms) - when it passes the launch proceeds.
*/
u32 dropped_pages = 0;
+ bool bound_hit = false; /* GRFIX FIX1c: the absolute bound fired this
+ * pass - the launch proceeds, no hold */
/*
* GRFIX FIX1c (r213): detail for the first (up to 4) dropped pages,
* so the cycle records WHICH VAs and which candidate class dropped.
@@ -14826,7 +14833,44 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
svc_gr_data_stalled = (dropped_pages > 0) ||
(n_arg_hi > 0 && n_arg_hi_res == 0);
svc_fwd_req.gr_dropped = dropped_pages;
- if (dropped_pages > 0) {
+ /*
+ * GRFIX FIX1c (r214): the DECISION POINT IS SELF-ENFORCING. The
+ * absolute per-launch bound is consulted here - at the only place
+ * the stalled verdict is produced, before the GRFILL-HOLD line can
+ * be emitted and before any caller can act on the verdict - so no
+ * re-drive pass can bypass it. r214: the same launch re-filled
+ * ~2/s for 220 s with GRFILL-EXPIRED=0 because the a5715df1
+ * consume-tail resets wiped the per-launch record between passes
+ * while the entry index moved (107 -> 99) under pin-batch rewinds,
+ * so the bound svc_gr_request consulted was re-armed before it
+ * could pass. When the bound passes the launch PROCEEDS: the
+ * historical (pre-8b058884) forward path runs, exactly as if the
+ * fill had not stalled.
+ *
+ * GRFIX FIX1d (benign class): the observed drops (probe=none /
+ * walk rc=-2) are indistinguishable at fill time from a page
+ * whose pin simply has not landed yet - both have no source at
+ * this instant and the only discriminator is whether the pin
+ * arrives inside the window. A blanket "probe=none => never hold"
+ * would also disable the pin-late retry the hold exists for, so
+ * the absolute bound stays the only guard: benign drops cost at
+ * most gsp_phys_gr_hold_max_ms once per launch VA, then the
+ * launch proceeds.
+ */
+ if (svc_gr_data_stalled && ch &&
+ svc_gr_hold_bound_expired(ch, svc_fwd_req.gr_push_va)) {
+ svc.fwd_gr_hold_exp++;
+ bound_hit = true;
+ if (!ch->gr_hold_exp_logged) {
+ ch->gr_hold_exp_logged = true;
+ pr_info("vgsp-gr: GRFILL-EXPIRED launch=0x%llx dropped=%u waited_ms=%u\n",
+ svc_fwd_req.gr_push_va, dropped_pages,
+ jiffies_to_msecs(jiffies -
+ ch->gr_hold_dead_since));
+ }
+ svc_gr_data_stalled = false; /* proceed: forward */
+ }
+ if (dropped_pages > 0 && !bound_hit) {
pr_info_ratelimited("vgsp-gr: GRFILL-HOLD launch=0x%llx dropped=%u kept=%u\n",
svc_fwd_req.gr_push_va, dropped_pages,
svc_fwd_req.gr_n_data);
@@ -14851,6 +14895,9 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
pr_info("vgsp-sema: svc-gr data fill: %u candidate ptrs, %u pages resolved; %u high argument ptr(s), %u resolved; %u dropped page(s) -> launch held for a bounded retry\n",
n_cand, svc_fwd_req.gr_n_data, n_arg_hi, n_arg_hi_res,
dropped_pages);
+ else if (bound_hit)
+ pr_info_ratelimited("vgsp-sema: svc-gr data fill: %u candidate ptrs, %u pages resolved; %u dropped page(s); hold bound expired -> launch proceeds\n",
+ n_cand, svc_fwd_req.gr_n_data, dropped_pages);
else
pr_info("vgsp-sema: svc-gr data fill: %u candidate ptrs, %u pages resolved (reloc 0x%llx+)\n",
n_cand, svc_fwd_req.gr_n_data, reloc_base);
@@ -14969,7 +15016,14 @@ static int svc_gr_req_fill(struct nv_vgpu_device *vgpu,
if (!svc_gr_page_inline_covers(pg->va))
return -ENOENT;
}
- svc_gr_data_fill(vgpu);
+ /*
+ * GRFIX FIX1c: the fill hosts the self-enforcing decision point and
+ * therefore needs the channel's per-launch bound record. The const
+ * view exists for the read-only gates; the channel is the pump's
+ * mutable live bookkeeping object and this runs on the same
+ * service thread.
+ */
+ svc_gr_data_fill(vgpu, (struct svc_channel *)ch);
return 0;
}
@@ -17487,10 +17541,11 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
ch->gr_nocap_va = 0;
ch->unread_va = 0;
ch->unread_until = 0;
- /* GRFIX FIX1b: the entry is consumed; the per-launch
- * absolute-bound record resets with it. */
- ch->gr_hold_dead_va = 0;
- ch->gr_hold_exp_logged = false;
+ /* GRFIX FIX1c (r214): do NOT reset the per-launch
+ * bound record here - a consume of an unrelated entry
+ * would re-arm the held launch's bound every pass
+ * (see svc_fwd_hold_poll). Reset happens on channel
+ * (re)registration and the session diag reset. */
/* Publish progress the way the GPU would. */
g = ch->last_get;