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.c107
1 files changed, 106 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index f90ed2c..cb9d731 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -3530,6 +3530,9 @@ static inline bool svc_pool_pa_identity(u64 va, u64 pa)
static void svc_pool_boot_store(u64 va, u64 pa, int ap); /* m168 */
static bool svc_dst_guard_hold(u64 va); /* m169b */
+static bool svc_dst_guard_should_hold(u64 va); /* r609 */
+static void svc_dst_guard_age(void); /* r609 */
+static void svc_dst_guard_reset(void); /* r609 */
static bool svc_dst_guard_pending(u64 va); /* r231 */
static u32 svc_read_order_log; /* r231 budget */
static u32 svc_atrace_log; /* r234 A-TRACE budget */
@@ -6890,7 +6893,7 @@ static int svc_copy_1d(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t tot
if (dst_virt && dst_aperture == CE_APERTURE_VID &&
dst_prov >= 3 && dst_orig >= SVC_VAS_FLOOR &&
gsp_sema_copy_dst_pin_guard &&
- svc_dst_guard_hold(dst_orig)) {
+ svc_dst_guard_should_hold(dst_orig)) {
svc.copy_dst_hold++;
if (svc.copy_dst_hold <= 16)
pr_info("sema-svc: device-dst copy held: dst=0x%llx prov=%u (no pin yet; stale-table guard)\n",
@@ -12305,6 +12308,7 @@ static void svc_session_flush(void)
svc_gr_diag_reset(); /* m150: per-session diagnostic budgets */
svc_gr_defer_reset(); /* r604: per-session defer latches */
+ svc_dst_guard_reset(); /* r609: per-session device-dst windows */
svc.map_n = 0;
svc_pb_n = 0;
svc_pd_found = 0;
@@ -14833,6 +14837,88 @@ bool gsp_sema_wait_gate = 1;
unsigned gsp_sema_copy_dst_guard_ms = 3000;
/*
+ * r609: the m169 first-touch window is per PAGE, but the stale-table risk it
+ * covers is per CLIENT TABLE BUILD. The driver's H2D relocation burst on the
+ * eng==0 copy channel writes N distinct first-write pages back to back, and
+ * because the pump holds the FIRST held entry and the rest of the chain
+ * decodes only after it drains, each page paid its own full window,
+ * serialized (r606 red draw: `sema-pend: hold h=0x5c000059 idx=90` held
+ * 362167.7->362170.8, idx=92 held 362177.7->362182.9; the b H2D entry ran
+ * 362182.882, 326 ms AFTER the launch forward -> `VADD bad=32735
+ * csum=8139264`, c = a + 0). The guard's bet - a fresh pin lands inside the
+ * window - is a property of the client's table state, not of one page: once
+ * ONE device-dst page of a channel has waited the full window with NO pin
+ * arriving (every observed release logs "without a pin"), the same bet for
+ * the next page of the same burst is already lost. Age the channel for
+ * gsp_sema_copy_dst_age_ms after such a release; further first-write
+ * device-dst pages of that channel inside the window skip the hold and run
+ * with the walk translation - the exact translation the expired guard would
+ * have used anyway. The first page of every burst still pays the full
+ * window, so the anti-stale bet is unchanged; only the N x window
+ * serialization is removed (r606 class: ~20 s of chain -> one window).
+ * Keyed by h_object like every channel table; the session flush clears it,
+ * so a recycled handle can never inherit the previous client's ageing
+ * (the r604 lifetime lesson). 0 disables (= per-page windows, pre-r609).
+ */
+unsigned gsp_sema_copy_dst_age_ms = 3000;
+#define SVC_DST_AGE_SLOTS 16
+static u32 svc_dst_age_ch[SVC_DST_AGE_SLOTS];
+static unsigned long svc_dst_age_j[SVC_DST_AGE_SLOTS];
+static u32 svc_dst_age_pos;
+static u32 svc_dst_age_log;
+
+/* r609: the current decode channel's guard window expired without a pin. */
+static void svc_dst_guard_age(void)
+{
+ u32 i;
+
+ if (!gsp_sema_copy_dst_age_ms)
+ return;
+ for (i = 0; i < SVC_DST_AGE_SLOTS; i++)
+ if (svc_dst_age_ch[i] == svc.cur_ch) {
+ svc_dst_age_j[i] = jiffies;
+ return;
+ }
+ i = svc_dst_age_pos++ % SVC_DST_AGE_SLOTS;
+ svc_dst_age_ch[i] = svc.cur_ch;
+ svc_dst_age_j[i] = jiffies;
+}
+
+/* r609: is the current decode channel inside its post-expiry ageing window? */
+static bool svc_dst_guard_aged(void)
+{
+ unsigned long now = jiffies;
+ u32 i;
+
+ if (!gsp_sema_copy_dst_age_ms || !svc.cur_ch)
+ return false;
+ for (i = 0; i < SVC_DST_AGE_SLOTS; i++)
+ if (svc_dst_age_ch[i] == svc.cur_ch &&
+ time_before(now, svc_dst_age_j[i] +
+ msecs_to_jiffies(gsp_sema_copy_dst_age_ms)))
+ return true;
+ return false;
+}
+
+/*
+ * r609: decide whether a first-write device-dst page pays the m169 window.
+ * An aged channel skips it (the burst's first page already paid and no pin
+ * arrived); otherwise the normal per-page window runs.
+ */
+static bool svc_dst_guard_should_hold(u64 va)
+{
+ if (svc_dst_guard_aged()) {
+ if (svc_dst_age_log < 16) {
+ svc_dst_age_log++;
+ pr_info("sema-svc: device-dst guard age-skipped dst=0x%llx h=0x%x (same-channel burst after an un-pinned release; walk translation)\n",
+ va, svc.cur_ch);
+ }
+ return false;
+ }
+ return svc_dst_guard_hold(va);
+}
+
+/*
* r231 READ-ORDER guard (default 0: witness only). A device-src copy whose
* source VA has a PENDING device-dst write hold (the m169 guard window is
* still open) reads the PRE-write content: the writer's bytes land only
@@ -14881,6 +14967,7 @@ static bool svc_dst_guard_hold(u64 va)
if (svc_dst_guard[i].first) {
svc_dst_guard[i].first = 0;
svc.copy_dst_relaxed++;
+ svc_dst_guard_age(); /* r609: burst ageing */
pr_info("sema-svc: device-dst guard released without a pin va=0x%llx (using the walk translation)\n",
page);
}
@@ -14897,6 +14984,24 @@ static bool svc_dst_guard_hold(u64 va)
}
/*
+ * r609: clear the m169 page windows and the r609 ageing ring with the
+ * session. Both are keyed by VA page / h_object alone, and both would
+ * otherwise pre-age the next client's first touch (a page slot still inside
+ * its window makes the new client's first device-dst write skip the
+ * anti-stale wait; an ageing stamp makes the new channel's whole first
+ * burst skip it). The stale-table risk this guard covers is precisely the
+ * new-session condition, so the windows must start fresh.
+ */
+static void svc_dst_guard_reset(void)
+{
+ memset(svc_dst_guard, 0, sizeof(svc_dst_guard));
+ svc_dst_guard_next = 0;
+ memset(svc_dst_age_ch, 0, sizeof(svc_dst_age_ch));
+ memset(svc_dst_age_j, 0, sizeof(svc_dst_age_j));
+ svc_dst_age_pos = 0;
+}
+
+/*
* r231 READ-ORDER guard: true while a held device-dst write for this VA
* page is still inside its bounded window (the writer's bytes have not
* landed yet). See the gsp_sema_read_order_guard declaration.