diff options
| -rw-r--r-- | kernel/gsp_sema_service.c | 53 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.h | 8 | ||||
| -rw-r--r-- | kernel/main.c | 7 | ||||
| -rw-r--r-- | tools/guest-diag/guest_pmap_win.py | 38 | ||||
| -rw-r--r-- | tools/guest-diag/pin_gr_window.py | 13 |
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 |
