summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c53
1 files changed, 45 insertions, 8 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 1296f81..ce2e0c9 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -143,6 +143,10 @@ struct svc_channel {
u32 logged_expected; /* last pool value logged (rate limit) */
unsigned long rescue_last; /* rate limit for the full-RAM rescue scan */
u32 rescue_fail; /* consecutive failed rescues for the entry */
+ unsigned long defer_since; /* first failure of the pending GR entry
+ * (0 = none): the entry is left pending
+ * for the GR grace window so a late
+ * window pin can still make it readable */
u64 counter_pa; /* guest PA of the u32 GPU completion counter
* (registered via the sema_counter debug param);
* 0 = not registered */
@@ -3255,6 +3259,14 @@ static int svc_chan_entry0(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
#define SVC_GR_USERD_OFF 0x2000ULL
bool gsp_sema_gr_rings = true;
+/*
+ * GR (compute) entries whose push page is not translatable are left pending
+ * for this long before the pump consumes them as stale. The push pages are
+ * mapped and pinned by a host watcher from guest truth a moment after the
+ * channels appear; without the grace the first entries are consumed before
+ * the pin lands and the releases they carry are lost.
+ */
+unsigned gsp_sema_gr_grace_ms = 8000;
/*
* CE release fallback: when a push carrying a tracking-semaphore release
@@ -4029,7 +4041,12 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
kfree(pb);
break;
} else if (++ch->rescue_fail >=
- (ch->engine_type ? 2 : 1)) {
+ (ch->engine_type ? 2 : 1) &&
+ (ch->engine_type ||
+ (ch->defer_since &&
+ time_after(jiffies,
+ ch->defer_since +
+ msecs_to_jiffies(gsp_sema_gr_grace_ms))))) {
/*
* The slot no longer holds this
* push (overwritten buffer): the
@@ -4045,18 +4062,20 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
* cannot validate - and their
* completion signal is the
* per-channel counter we publish
- * from `put`. Consume on the
- * first failed attempt: a slow
- * skip delays GPGet and the
- * counter long enough for the
- * client's submission wait to
- * expire (observed at ~12 s with
- * the 3-attempt path).
+ * from `put`. The entry is left
+ * pending for a grace window
+ * first: the push pages are
+ * pinned from guest truth a
+ * moment after the channels
+ * appear, and only a readable
+ * push carries the releases the
+ * client waits on.
*/
pr_info("sema-chan: skipping stale entry h=0x%x va=0x%llx len=%u after %u failed rescues\n",
ch->h_object, va, len,
ch->rescue_fail);
ch->rescue_fail = 0;
+ ch->defer_since = 0;
if (gsp_sema_fake_rel)
svc_fake_release(vgpu,
ch);
@@ -4071,6 +4090,21 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
kfree(pb);
continue;
} else {
+ /*
+ * First failure (CE) or
+ * inside the GR grace window:
+ * leave the entry pending so
+ * a translation that lands
+ * shortly still gets the push
+ * executed. The completion
+ * counter is published from
+ * `put` at the end of the pass
+ * either way.
+ */
+ if (!ch->engine_type &&
+ !ch->defer_since)
+ ch->defer_since =
+ jiffies;
svc.gpfifo_nomap++;
kfree(pb);
break;
@@ -4081,6 +4115,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
}
ch->last_get = (idx + 1) % ch->gpfifo_entries;
+ ch->rescue_fail = 0;
+ ch->defer_since = 0;
/* Publish progress the way the GPU would. */
g = ch->last_get;
@@ -4118,6 +4154,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc.chan[k].last_rel_va = ch->last_rel_va;
svc.chan[k].rescue_last = ch->rescue_last;
svc.chan[k].rescue_fail = ch->rescue_fail;
+ svc.chan[k].defer_since = ch->defer_since;
break;
}
}