summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_sema_service.c53
-rw-r--r--kernel/gsp_sema_service.h8
-rw-r--r--kernel/main.c7
-rw-r--r--tools/guest-diag/guest_pmap_win.py38
-rw-r--r--tools/guest-diag/pin_gr_window.py13
5 files changed, 100 insertions, 19 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;
}
}
diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h
index 3b85591..8cd9e61 100644
--- a/kernel/gsp_sema_service.h
+++ b/kernel/gsp_sema_service.h
@@ -77,4 +77,12 @@ extern bool gsp_sema_gr_rings;
*/
extern bool gsp_sema_fake_rel;
+/*
+ * Grace window (ms) an untranslatable GR GPFIFO entry is left pending before
+ * the pump consumes it as stale. The GR push pages are pinned from guest
+ * truth a moment after the channels appear; the window lets those pins land
+ * so the releases inside the pushes are applied.
+ */
+extern unsigned gsp_sema_gr_grace_ms;
+
#endif /* _GSP_SEMA_SERVICE_H_ */
diff --git a/kernel/main.c b/kernel/main.c
index 726b4bf..952daf1 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -2441,6 +2441,13 @@ module_param_named(sema_fake_rel, gsp_sema_fake_rel, bool, 0644);
MODULE_PARM_DESC(sema_fake_rel, "Acknowledge unreadable CE releases directly (default 0)");
/*
+ * Grace window (ms) an untranslatable GR entry stays pending before the pump
+ * consumes it as stale, so a late push-buffer pin can still make it readable.
+ */
+module_param_named(sema_gr_grace_ms, gsp_sema_gr_grace_ms, uint, 0644);
+MODULE_PARM_DESC(sema_gr_grace_ms, "GR pending-entry grace window in ms (default 8000)");
+
+/*
* Debug: inject a verified {GPU VA -> guest PA} translation into the
* semaphore service (used when the client's mapping cannot be discovered
* from guest structures):
diff --git a/tools/guest-diag/guest_pmap_win.py b/tools/guest-diag/guest_pmap_win.py
index a9b74a7..f6ca85c 100644
--- a/tools/guest-diag/guest_pmap_win.py
+++ b/tools/guest-diag/guest_pmap_win.py
@@ -4,8 +4,9 @@
# pread) so a 256 MB window takes about a second, not minutes.
#
# Usage: sudo python3 guest_pmap_win.py <pid> <lo-hex> <hi-hex> [max-pairs] [pa-max-hex]
-# Output: one "0x<va>,0x<pa>" line per present page (ascending VA), capped at
-# max-pairs. PAs of 0 are skipped; pages above pa-max are skipped unless 0.
+# Output: one "0x<va>,0x<pa>,<npages>" line per contiguous run (ascending VA),
+# capped at max-pairs pages. PAs of 0 are skipped; pages at/above pa-max are
+# skipped unless pa-max is 0.
import os
import sys
@@ -17,6 +18,16 @@ pa_max = int(sys.argv[5], 16) if len(sys.argv) > 5 else 0
BATCH = 512
out = []
+run_va = run_pa = None
+run_n = 0
+pairs = 0
+
+
+def flush():
+ if run_n:
+ out.append('0x%x,0x%x,%d' % (run_va, run_pa, run_n))
+
+
fd = os.open('/proc/%d/pagemap' % pid, os.O_RDONLY)
try:
va = lo
@@ -29,19 +40,32 @@ try:
got = len(data) // 8
for i in range(got):
e = int.from_bytes(data[i * 8:i * 8 + 8], 'little')
+ page_va = va + i * 0x1000
if not ((e >> 63) & 1):
+ flush()
+ run_va = run_pa = None
+ run_n = 0
continue
pfn = e & ((1 << 55) - 1)
pa = pfn << 12
- if not pa:
- continue
- if pa_max and pa >= pa_max:
+ if not pa or (pa_max and pa >= pa_max):
+ flush()
+ run_va = run_pa = None
+ run_n = 0
continue
- out.append('0x%x,0x%x' % (va + i * 0x1000, pa))
- if len(out) >= maxp:
+ if (run_va is not None and page_va == run_va + run_n * 0x1000
+ and pa == run_pa + run_n * 0x1000):
+ run_n += 1
+ else:
+ flush()
+ run_va, run_pa, run_n = page_va, pa, 1
+ pairs += 1
+ if pairs >= maxp:
+ flush()
print('\n'.join(out))
sys.exit(0)
va += got * 0x1000
finally:
os.close(fd)
+flush()
print('\n'.join(out))
diff --git a/tools/guest-diag/pin_gr_window.py b/tools/guest-diag/pin_gr_window.py
index 4a968c9..26083f7 100644
--- a/tools/guest-diag/pin_gr_window.py
+++ b/tools/guest-diag/pin_gr_window.py
@@ -77,9 +77,14 @@ def scan(pid):
% (pid, LO, HI, MAXP, PAMAX), 90)
pairs = []
for line in out.splitlines():
- m = re.match(r"^(0x[0-9a-f]+),(0x[0-9a-f]+)$", line.strip())
- if m:
- pairs.append((int(m.group(1), 16), int(m.group(2), 16)))
+ m = re.match(r"^(0x[0-9a-f]+),(0x[0-9a-f]+)(?:,(\d+))?$", line.strip())
+ if not m:
+ continue
+ va = int(m.group(1), 16)
+ pa = int(m.group(2), 16)
+ n = int(m.group(3)) if m.group(3) else 1
+ for i in range(n):
+ pairs.append((va + i * 0x1000, pa + i * 0x1000))
return pairs
@@ -125,7 +130,7 @@ def probe(va):
def main():
- interval = float(sys.argv[1]) if len(sys.argv) > 1 else 2.0
+ interval = float(sys.argv[1]) if len(sys.argv) > 1 else 1.0
if not push_helper():
log("FATAL: could not push guest helper")
return 1