summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-19 07:57:32 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-19 07:57:32 -0400
commitc1350b040f740f3aeb426bf8407ab930f5e87c28 (patch)
treecf5ad3e8eb2a470395bac72270b5128973c94076 /kernel
parent459384e02bba4eca04fa3eca2365a731a4a7a33a (diff)
downloadopen-iov-c1350b040f740f3aeb426bf8407ab930f5e87c28.tar.gz
open-iov-c1350b040f740f3aeb426bf8407ab930f5e87c28.zip
vgsp: newbind holds are residual-only and short (r237 T2 3 s GP_GET delay)stallfree
r237-2: T2's GR channel carried T1's residual put=115; my 3 s empty-decode hold delayed the host's GP_GET during the residual walk, and the guest unwound at binding+3.46 s (zeroed PROMOTE_CTX, then full FREE) - exactly when the host finally consumed the residual. The guest's ctx-init patience is ~3 s, so the hold must never delay the walk that long. - New SVC_GR_NEWBIND_HOLD_MS 1200u and per-channel wd_newbind_hold_until: the hold windows (empty-decode and unmapped entry) now apply only while it is fresh (<1.2 s; the rebuild lands in ~0.8 s) and only when put == get (residual context, no producer work pending). Any pending producer work is walked without delay, so GP_GET always advances promptly. - wd_newbind_until (3 s) still governs retry eligibility; the opdef drop, chanswitch log, pending-map/rebuild path are unchanged. make kernel green.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 6e37b2f..0520c4f 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -425,6 +425,9 @@ struct svc_channel {
* must reconcile the binding before the walk
* (drop dead opdef slots whose since predates
* the binding; log the transition) */
+ unsigned long wd_newbind_hold_until; /* short hold window inside
+ * wd_newbind_until (residual-only,
+ * put==get; never delays fresh work) */
unsigned long wd_newbind_until; /* STALLFREE: freshness window of a
* new binding; inside it an
* unmapped/undecoded GR entry is held
@@ -16604,6 +16607,15 @@ static void svc_userd_sweep(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
* window of extra latency on first contact.
*/
#define SVC_GR_NEWBIND_MS 3000u
+/*
+ * STALLFREE r237: the HOLD part of the window must be shorter than the
+ * window itself. r237-2: the 3 s hold on T2's residual ring delayed its
+ * GP_GET past the guest's ~3 s ctx-init patience (T2 unwound with a
+ * zeroed PROMOTE_CTX at binding+3.46 s, exactly when the host finally
+ * consumed the residual). The guest needs GP_GET to advance promptly;
+ * the rebuild lands in ~0.8 s, so 1.2 s is enough for one attempt.
+ */
+#define SVC_GR_NEWBIND_HOLD_MS 1200u
static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu,
struct svc_channel *ch, u32 put, u32 get)
@@ -17195,6 +17207,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc_opdef_drop_channel(vgpu, ch->h_object, jiffies);
ch->wd_newbind_until = jiffies +
msecs_to_jiffies(SVC_GR_NEWBIND_MS);
+ ch->wd_newbind_hold_until = jiffies +
+ msecs_to_jiffies(SVC_GR_NEWBIND_HOLD_MS);
/*
* Bounded proof (r234 asks): the window was armed for
* THIS binding; if a later stall shows no such line,
@@ -17719,9 +17733,10 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
!entry_replay &&
svc_rel_count == rel_n_iter &&
svc_gr_qmd_seen == 0 &&
- ch->wd_newbind_until &&
+ put == get &&
+ ch->wd_newbind_hold_until &&
time_before(jiffies,
- ch->wd_newbind_until)) {
+ ch->wd_newbind_hold_until)) {
if (!ch->defer_since)
ch->defer_since =
jiffies;
@@ -18805,9 +18820,10 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
* the rebuild caught up).
*/
if (!ch->engine_type &&
- ch->wd_newbind_until &&
+ put == get &&
+ ch->wd_newbind_hold_until &&
time_before(jiffies,
- ch->wd_newbind_until)) {
+ ch->wd_newbind_hold_until)) {
svc.rebuild_now = true;
if (svc.gr_pending_map < 16) {
svc.gr_pending_map++;
@@ -19045,6 +19061,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc.chan[k].wd_nocap_put = ch->wd_nocap_put;
svc.chan[k].wd_chanswitch = ch->wd_chanswitch;
svc.chan[k].wd_newbind_until = ch->wd_newbind_until;
+ svc.chan[k].wd_newbind_hold_until =
+ ch->wd_newbind_hold_until;
svc.chan[k].pushpg_va = ch->pushpg_va;
svc.chan[k].pushpg_n = ch->pushpg_n;
svc.chan[k].content_max = ch->content_max;