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.c59
1 files changed, 50 insertions, 9 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 30b349b..5e887f1 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -1298,7 +1298,23 @@ static int svc_walk_vaspaces(struct nv_vgpu_device *vgpu, u64 va,
static u64 svc_pd_base;
static int svc_pd_ap;
static u32 svc_pd_entries;
-static u8 svc_pd_tried;
+/*
+ * Discovery is retryable, not one-shot (ISSUE-0001 durable direction).
+ *
+ * The first call can happen before the client has written the page tables
+ * (the sva/spa samples do not exist yet) or before enough verified pairs are
+ * known; the old latch (`svc_pd_tried = 1` before any scan) then disabled the
+ * only kernel-native source that covers pool/push windows the content-scanned
+ * map and the published directories miss, for the rest of the boot, even
+ * though the samples it needs appear seconds later. Re-arm on new evidence
+ * instead: an attempt that could not run does not latch, and a scan runs only
+ * when the sample set changed since the last one (fingerprint), bounded by
+ * SVC_PD_ATTEMPTS_MAX scans per boot - the same order as the old
+ * one-per-pairing re-arm.
+ */
+#define SVC_PD_ATTEMPTS_MAX 8
+static u8 svc_pd_attempts; /* scans actually run (not sample misses) */
+static u64 svc_pd_ev_hash; /* fingerprint of the sample set last scanned */
static u8 svc_pd_found;
#define SVC_PD_SAMPLES 8
#define SVC_PD_MIN_HITS 4
@@ -1343,9 +1359,8 @@ static void svc_pd_discover(struct nv_vgpu_device *vgpu)
u8 *buf;
int pass;
- if (svc_pd_tried)
+ if (svc_pd_found || svc_pd_attempts >= SVC_PD_ATTEMPTS_MAX)
return;
- svc_pd_tried = 1;
/*
* Pinned push-buffer pairs are the strongest samples available: they
@@ -1365,7 +1380,7 @@ static void svc_pd_discover(struct nv_vgpu_device *vgpu)
if (n < SVC_PD_MIN_HITS) {
n = 0;
if (svc.map_n < SVC_PD_SAMPLES)
- return;
+ return; /* no evidence yet: retry when pairs appear */
step = svc.map_n / SVC_PD_SAMPLES;
for (i = 0; i < SVC_PD_SAMPLES; i++) {
sva[i] = svc.map[i * step].gpu_page;
@@ -1377,6 +1392,24 @@ static void svc_pd_discover(struct nv_vgpu_device *vgpu)
}
if (!n)
return;
+ /*
+ * One scan per distinct sample set: a miss on the same evidence cannot
+ * succeed on a retry, and the scan costs a full RAM walk. A changed
+ * sample set (a new pinned pair, or a rebuilt map) is new evidence and
+ * re-arms the scan. The fingerprint uses the values, not just the
+ * count, because reaching four pinned pairs replaces the map samples
+ * one-for-one and can leave the count unchanged.
+ */
+ {
+ u64 ev = n;
+
+ for (i = 0; i < n; i++)
+ ev = (ev + sva[i] + (spa[i] << 12)) * 1000003;
+ if (svc_pd_attempts && ev == svc_pd_ev_hash)
+ return;
+ svc_pd_ev_hash = ev;
+ }
+ svc_pd_attempts++;
/* Guest RAM first, then the emulated vidmem. Page directories are page
* aligned, and every VA here is below 2^47, so the root entry that
@@ -1970,7 +2003,14 @@ static int svc_lookup_trusted(struct nv_vgpu_device *vgpu, u64 va, u64 *addr,
svc_lat_store(va, *addr, *ap);
return 0;
}
- if (!svc_pd_tried) {
+ if (!svc_pd_found) {
+ /*
+ * Retryable discovery: on a boot where the directory is found
+ * only after the client's page tables appear, a later call
+ * with fresh verified pairs re-runs the scan. svc_pd_discover
+ * self-gates (evidence, attempt cap), so this is cheap when
+ * nothing changed.
+ */
svc_pd_discover(vgpu);
if (!svc_walk_discovered(vgpu, va & ~0xfffULL, addr, ap)) {
*addr += va & 0xfff;
@@ -7594,11 +7634,12 @@ static void svc_pb_pair(struct nv_vgpu_device *vgpu, struct svc_channel *ch)
/*
* The pinned pairs are verified samples of UVM's own page directory;
- * let the directory discovery run again with them, so the walk can
- * translate the parts of the pool no base page describes.
+ * the next discovery call sees the grown sample set as fresh evidence
+ * and re-runs the scan (svc_pd_discover's attempt/evidence gates keep
+ * that bounded), so the walk can translate the parts of the pool no
+ * base page describes. On the old one-shot latch this pairing was the
+ * only re-arm; the retryable discovery no longer needs it.
*/
- if (!svc_pd_found)
- svc_pd_tried = 0;
pr_info("sema-svc: push-buffer pinned h=0x%x rank=%u slot=%u va=0x%llx -> pa=0x%llx (first push len=%u)\n",
ch->h_object, ch->ce_index, want, va, hit_pa, len);