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.c353
1 files changed, 338 insertions, 15 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index b6fa436..90ea545 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -88,6 +88,20 @@ static inline u64 svc_fb_shadow_size(const struct nv_vgpu_device *vgpu)
#define SEMA_VA_LO 0x100000000ULL
#define SEMA_VA_HI 0x2000000000ULL
+/*
+ * session 79: the GR/GL ucode init releases target the RM's LOW aperture
+ * (the same 0x4000000-0x4ffffff VA family as the push/ring windows): the
+ * live GL init push carries `2005c017 04923060 ... 02000001` (0x5c-form,
+ * va=0x4923060, payload 1, RELEASE) and `200426c0 00000000 04b19b10
+ * 00000001 10000000` (REPORT_SEM group, va=0x4b19b10, payload 1,
+ * RELEASE) - both rejected by the sysmem-only range check, so the GR
+ * completion never applied and the NvOgl engine-init wait spun forever.
+ * Accept the low aperture for release decode (the pushes are only
+ * decoded from trusted ring reads, so the false-positive risk the
+ * sysmem bound guarded against does not apply here).
+ */
+#define SVC_LOW_REL_VA_LO 0x4000000ULL
+
/* Canonical kernel virtual address range (x86_64). */
#define KVA_LO 0xffff800000000000ULL
#define KVA_HI 0xffffc00000000000ULL
@@ -1572,12 +1586,26 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc)
* channel; the stashed geometry survives, so the scrub path
* does not depend on the channel-table identity at all.
*/
- if (desc->gpfifo_entries >= 4096 && desc->gpfifo_va &&
+ /*
+ * m112b: the CeUtils scrubber is the ONLY exactly-4096-entry
+ * channel (NUM_COPY_BLOCKS). The old `>= 4096` test also
+ * matched every client channel (this driver version: 32768
+ * entries, not the 1024 the comment below assumed), so the
+ * single scrub slot bound to whichever client channel
+ * registered last (observed r701: the slot held h=0xbeee0102
+ * userd=0x8f400/entries=32768 and the pass authored put=0 for
+ * the wrong channel while the real scrubber's payload stayed
+ * zero - the vkAllocateMemory -2 gate).
+ */
+ if (desc->gpfifo_entries == 4096 && desc->gpfifo_va &&
desc->userd_pa) {
struct svc_scrub *s = svc_scrub_get(desc->vgpu, true);
if (!s)
goto scrub_done; /* table full: max guests */
+ pr_info("sema-svc: scrub stash bind vgpu=%px slot=%d h=0x%x entries=%u\n",
+ (void *)desc->vgpu, (int)(s - svc_scrubs),
+ desc->h_object, desc->gpfifo_entries);
/* Re-seed the counting on a fresh scrubber object or a
* new client session (m176: the counter/submitted state
* is per-session; a recycled scrubber handle after a
@@ -1602,6 +1630,16 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc)
desc->h_object, desc->gpfifo_va,
desc->gpfifo_entries, desc->userd_pa,
s->userd_as);
+ } else if (desc->gpfifo_entries >= 4096 &&
+ desc->gpfifo_entries != 32768) {
+ /* m112b: a non-32768 channel with >=4096 entries that
+ * fails the stash condition (missing VA or USERD PA)
+ * is a scrubber candidate the service cannot author
+ * for - log it so a silent no-authoring boot is
+ * diagnosable. */
+ pr_info_ratelimited("sema-svc: scrubber-stash MISS h=0x%x entries=%u va=0x%llx userd_pa=0x%llx\n",
+ desc->h_object, desc->gpfifo_entries,
+ desc->gpfifo_va, desc->userd_pa);
}
scrub_done:
pr_info("sema-svc: channel 0x%x registered gpfifo=0x%llx entries=%u userd=0x%llx eng=%u cid=%u notif=0x%llx\n",
@@ -1800,6 +1838,17 @@ void gsp_sema_service_vaspace_candidate_add(u32 h_vaspace, u64 pdb,
* the lesser evil; it is logged loudly for the record.
*/
#define SVC_VAS_CAND_AGE_MS 15000u
+/*
+ * r705h: the candidate age-out deadline is runtime-tunable. The parked
+ * COPY_SERVER_PDES candidate for the GL/Vulkan client ages out (UNVERIFIED)
+ * at exactly the moment the client's channels first register, so the
+ * content-verified walk can never anchor it; raising the deadline keeps the
+ * candidate parked until a host tool supplies a verified ring pair via
+ * sema_pdb_discover. 0 disables the age-out entirely.
+ */
+static u32 svc_vas_cand_age_ms = SVC_VAS_CAND_AGE_MS;
+module_param_named(sema_vas_cand_ms, svc_vas_cand_age_ms, uint, 0644);
+MODULE_PARM_DESC(sema_vas_cand_ms, "Parked-VAS-candidate age-out (ms, default 15000; 0 = never)");
static void svc_vas_candidates_age_out(struct nv_vgpu_device *vgpu)
{
@@ -1810,8 +1859,9 @@ static void svc_vas_candidates_age_out(struct nv_vgpu_device *vgpu)
if (!svc_vas_cand[i].valid)
continue;
- if (time_before(jiffies, svc_vas_cand[i].stamp +
- msecs_to_jiffies(SVC_VAS_CAND_AGE_MS)))
+ if (!svc_vas_cand_age_ms ||
+ time_before(jiffies, svc_vas_cand[i].stamp +
+ msecs_to_jiffies(svc_vas_cand_age_ms)))
continue;
memset(&d, 0, sizeof(d));
d.h_vaspace = svc_vas_cand[i].h_vaspace;
@@ -1819,7 +1869,7 @@ static void svc_vas_candidates_age_out(struct nv_vgpu_device *vgpu)
d.num_entries = svc_vas_cand[i].entries;
d.b_vidmem = svc_vas_cand[i].vidmem;
pr_warn("sema-svc: VAS 0x%x page directory registered UNVERIFIED after %u ms parked (pdb=0x%llx entries=%u; the content-verified ring walk never anchored this boot)\n",
- d.h_vaspace, SVC_VAS_CAND_AGE_MS, d.pdb,
+ d.h_vaspace, svc_vas_cand_age_ms, d.pdb,
d.num_entries);
gsp_sema_service_vaspace_add(&d);
svc_vas_cand[i].valid = false;
@@ -2970,6 +3020,11 @@ struct svc_ipin_alt {
static struct svc_ipin_alt svc_ipin_alt[SVC_IPIN_ALT_SLOTS];
static u64 svc_pushalt_hits; /* push reads served by a displaced pair */
static u32 svc_pushalt_log;
+/* r707x: per-client push-read attempt witness (pump read site). */
+static u32 svc_rdw_log;
+static u8 svc_read_last_src;
+/* r707d: bounded push-read failure witness (see svc_read_va_push_ex). */
+static u32 svc_pushfail_log;
static int svc_ipin_alt_lookup(u64 va, u64 *pa, int *ap)
{
@@ -10760,7 +10815,8 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
if ((op == HOST_SEM_OP_RELEASE ||
op == HOST_SEM_OP_REDUCTION) && payload &&
- va >= SEMA_VA_LO && va < SEMA_VA_HI) {
+ (va >= SEMA_VA_LO || va >= SVC_LOW_REL_VA_LO) &&
+ va < SEMA_VA_HI) {
if (page_pa)
svc_mark_hot(page_pa);
svc.pushes_seen++;
@@ -10953,7 +11009,9 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
break;
va = ((u64)st.rs_upper << 32) |
st.rs_lower;
- if (va < SEMA_VA_LO || va >= SEMA_VA_HI)
+ if ((va < SEMA_VA_LO &&
+ va < SVC_LOW_REL_VA_LO) ||
+ va >= SEMA_VA_HI)
break;
if (page_pa)
svc_mark_hot(page_pa);
@@ -12638,6 +12696,9 @@ static void svc_gr_defer_reset(void);
static void svc_session_flush(void)
{
+ /* r707x: per-client witness budgets. */
+ svc_pushfail_log = 0;
+ svc_rdw_log = 0;
unsigned long flags;
u32 i;
@@ -13867,6 +13928,21 @@ static u32 svc_pushpg_split_log;
* validated candidate). Reads stay defensively copied through
* svc_read_ap()/vfio_dma_rw(), which enforce the aperture bounds.
*/
+/* r707d: bounded push-read failure witness (see below). */
+static u32 svc_pushfail_log;
+/*
+ * r707e: last content-backed ring pair resolved by any channel. The VAS
+ * candidate verify is retried with it on EVERY pump pass: the parked
+ * COPY_SERVER_PDES candidate for the client's user VAS parks at
+ * device-create and must register before the submit's first push read
+ * (a failed GR entry read is never retried with a fresh VAS), but the ring
+ * resolution and the park race within one pass - the every-pass retry
+ * closes that race in a single boot.
+ */
+static u64 svc_lastgood_ring_va;
+static u64 svc_lastgood_ring_pa;
+
+
static int svc_read_va_push_ex(struct nv_vgpu_device *vgpu,
struct svc_channel *ch, u64 va, void *buf,
size_t len, bool skip_ipin)
@@ -13882,6 +13958,7 @@ static int svc_read_va_push_ex(struct nv_vgpu_device *vgpu,
bool have_win, done = false;
bool first = (p == buf);
int last_rc = -ENOENT;
+ int trusted_rc = 0;
u32 src;
have_win = !svc_pb_win_lookup(ch, page_va, &win_pa);
@@ -13935,7 +14012,9 @@ static int svc_read_va_push_ex(struct nv_vgpu_device *vgpu,
default:
/* learned cache / discovered map / page
* directories / targeted rm_mem resolve */
- if (svc_lookup_trusted(vgpu, va, &pa, &ap))
+ trusted_rc = svc_lookup_trusted(vgpu, va,
+ &pa, &ap);
+ if (trusted_rc)
continue;
break;
}
@@ -13996,10 +14075,33 @@ static int svc_read_va_push_ex(struct nv_vgpu_device *vgpu,
*/
if (src == 3 && first && !memchr_inv(p, 0, chunk))
continue;
+ svc_read_last_src = (u8)src;
done = true;
}
- if (!done)
+ if (!done) {
+ svc_read_last_src = 0xff;
+ if (svc_pushfail_log < 96) {
+ u64 ipa = 0, apa = 0;
+ int iap = 0, aap = 0;
+ bool has_ipin =
+ (svc_ipin_lookup(va, &ipa, &iap) == 0);
+ bool has_alt =
+ (svc_ipin_alt_lookup(va, &apa, &aap) == 0);
+
+ svc_pushfail_log++;
+ pr_info("sema-pushfail: va=0x%llx chunk=0x%llx page=0x%llx last_rc=%d trusted_rc=%d ipin=%d pa=0x%llx alt=%d pa=0x%llx win=%d pa=0x%llx\n",
+ (unsigned long long)va,
+ (unsigned long long)chunk,
+ (unsigned long long)page_va,
+ last_rc, trusted_rc, has_ipin,
+ (unsigned long long)ipa,
+ has_alt,
+ (unsigned long long)apa,
+ have_win,
+ (unsigned long long)win_pa);
+ }
return last_rc;
+ }
p += chunk;
va += chunk;
len -= chunk;
@@ -15580,6 +15682,58 @@ static bool svc_gr_ram_ring_scan(struct nv_vgpu_device *vgpu,
}
/*
+ * r705h: host-triggered pdb discovery. The automatic latch
+ * (svc_vas_candidates_verify + svc_xvas_pdb_discover) only runs from the RAM
+ * ring scan, which sweeps [0,6GB) before the client's pushes exist and then
+ * gives up for the boot; and per-client VAS state is flushed at session end.
+ * This entry point lets a host tool that CONTENT-LOCATED a verified
+ * {ring VA -> ring PA} pair (the ring page's GPFIFO entries are its
+ * fingerprint) hand the pair to the service while the client is alive, so:
+ * 1. every parked COPY_SERVER_PDES candidate is verified against the pair
+ * (fast: a walk each), and
+ * 2. if none verifies, the vidmem walk-root sweep anchors on the pair.
+ * Registered VASes make the client's pushbuffer VAs walkable and the pump
+ * can then decode the submit's pushes (the fence release among them).
+ */
+static u64 svc_pdb_disc_va;
+static u64 svc_pdb_disc_pa;
+static bool svc_pdb_disc_pending;
+
+/*
+ * r707r: bounded channel rewind (debug). After the VAS pdb anchor lands,
+ * entries skipped before it never re-decode on their own (their unread
+ * window expires into a skip), so the release they carry would be lost for
+ * that put epoch. A host tool asks for a rewind (sema_chan_rewind: a hex
+ * h_object, or "all"); the pump re-processes the channel from slot 0 with
+ * the consumed-slot bitmap and the per-entry rescue state cleared.
+ */
+static u32 svc_rewind_h;
+static bool svc_rewind_all;
+static bool svc_rewind_pending;
+
+int gsp_sema_service_chan_rewind(u32 h_object)
+{
+ if (!svc.task)
+ return -ENODEV;
+ svc_rewind_h = h_object;
+ svc_rewind_all = (h_object == 0xffffffffu);
+ svc_rewind_pending = true;
+ wake_up_process(svc.task);
+ return 0;
+}
+
+int gsp_sema_service_pdb_discover(u64 ring_va, u64 ring_pa)
+{
+ if (!svc.task)
+ return -ENODEV;
+ svc_pdb_disc_va = ring_va & ~0xfffULL;
+ svc_pdb_disc_pa = ring_pa & ~0xfffULL;
+ svc_pdb_disc_pending = true;
+ wake_up_process(svc.task);
+ return 0;
+}
+
+/*
* r496f: discover a kernel-RM client VAS's page directory in the emulated
* VRAM by verification. The CPU RM builds internal-VAS page tables in
* vidmem and never publishes them (SET_PAGE_DIRECTORY is an externally
@@ -23493,6 +23647,15 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu,
static void svc_pump_channels(struct nv_vgpu_device *vgpu)
{
+ if (svc_pdb_disc_pending) {
+ svc_pdb_disc_pending = false;
+ pr_info("sema-pdb-disc: requested va=0x%llx pa=0x%llx\n",
+ svc_pdb_disc_va, svc_pdb_disc_pa);
+ svc_vas_candidates_verify(vgpu, svc_pdb_disc_va,
+ svc_pdb_disc_pa);
+ svc_xvas_pdb_discover(vgpu, svc_pdb_disc_va,
+ svc_pdb_disc_pa);
+ }
/* Only ever called from the service thread. */
static struct svc_channel local[SVC_MAX_CHANNELS];
/*
@@ -23506,6 +23669,36 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
bool stalled = false;
spin_lock_irqsave(&svc.chan_lock, flags);
+ if (svc_rewind_pending) {
+ svc_rewind_pending = false;
+ for (i = 0; i < SVC_MAX_CHANNELS; i++) {
+ struct svc_channel *c = &svc.chan[i];
+
+ if (!c->valid || c->vgpu != vgpu)
+ continue;
+ if (!svc_rewind_all && c->h_object != svc_rewind_h)
+ continue;
+ pr_info("sema-chan: rewind h=0x%x last_get=%u put=%u (slot bitmap + rescue state cleared)\n",
+ c->h_object,
+ (unsigned int)c->last_get,
+ (unsigned int)c->put_prev);
+ bitmap_zero(c->slot_done_epoch, SVC_GPFIFO_MAX_BITS);
+ c->last_get = 0;
+ c->rescue_fail = 0;
+ c->unread_va = 0;
+ c->unread_until = 0;
+ c->defer_since = 0;
+ }
+ }
+ /*
+ * r707e: every-pass candidate verify with the last-good ring pair.
+ * Cheap (<=16 parked candidates, one walk each) and idempotent; the
+ * first pass after the user-VAS candidate parks registers it, so the
+ * client's very first push reads resolve.
+ */
+ if (svc_lastgood_ring_pa)
+ svc_vas_candidates_verify(vgpu, svc_lastgood_ring_va,
+ svc_lastgood_ring_pa);
/*
* r507o stream-order: walk the CE channels BEFORE the GR channels.
* The client's stream order places its H2D copies before the kernel
@@ -23723,6 +23916,25 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
if (!rrc)
svc_pb_pair(vgpu, ch);
+ if (!rrc && ring_pa) {
+ svc_lastgood_ring_va = ch->gpfifo_va;
+ svc_lastgood_ring_pa = ring_pa;
+ }
+ /*
+ * r707f (FOLD): the moment ANY channel's ring resolves through
+ * the channel object, verify the parked COPY_SERVER_PDES VAS
+ * candidates against that content-backed pair. The candidates
+ * are parked at device-create time, before the client's compute
+ * channels first submit, so registering here lands the VAS page
+ * directory BEFORE the submit's entries get their first push
+ * read - the window the host-triggered path could not win (the
+ * entry's first read and the ring's first resolution happen in
+ * the same pass; a pair that arrives later cannot help, because
+ * a failed GR entry read is never retried with the fresh VAS).
+ */
+ if (!rrc)
+ svc_vas_candidates_verify(vgpu, ch->gpfifo_va,
+ ring_pa);
/*
* ISSUE-0002 (r47 diag): run the deferred CE USERD sweep for a
@@ -24212,9 +24424,21 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
if (pb) {
int rescue_rc;
- bool unreadable =
- svc_read_va_push(vgpu, ch, va,
- pb, len) != 0;
+ int rd_rc;
+ bool unreadable;
+
+ svc_read_last_src = 0xff;
+ rd_rc = svc_read_va_push(vgpu, ch, va,
+ pb, len);
+ unreadable = rd_rc != 0;
+ if (gsp_sema_dbg && svc_rdw_log < 6000 &&
+ !ch->engine_type) {
+ svc_rdw_log++;
+ pr_info("sema-rdw: h=0x%x va=0x%llx len=%u rc=%d src=%u\n",
+ ch->h_object, va, len,
+ rd_rc,
+ (unsigned)svc_read_last_src);
+ }
bool injected = false;
bool allow_ops = (ch->engine_type != 0);
@@ -24282,7 +24506,82 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
kfree(fb);
}
} else {
- unreadable = true;
+ /*
+ * r707v: a primary-source
+ * hit (injected pin, window
+ * guess, lat cache) whose
+ * content is implausible
+ * must not shadow the
+ * registered VAS walk - a
+ * stale pin otherwise makes
+ * every push read "resolve"
+ * to the wrong page, fail
+ * plausibility and turn the
+ * entry unreadable forever.
+ * Retry once with the pins
+ * bypassed so the trusted
+ * walk (svc_walk_vaspaces)
+ * answers; accept only a
+ * plausible stream.
+ */
+ u8 *vb = kmalloc(len,
+ GFP_KERNEL);
+
+ if (vb) {
+ u64 wpa = 0;
+ int wap = SVC_APERTURE_SYS;
+ bool ok = false;
+
+ /*
+ * r707w: consult ONLY the
+ * registered VAS walk (the
+ * exact path walk_probe
+ * proves) - not
+ * svc_lookup_trusted, whose
+ * pin/lat hits would answer
+ * with the same wrong page
+ * again and keep the entry
+ * unreadable.
+ */
+ int wr = svc_walk_vaspaces(vgpu,
+ va & ~0xfffULL,
+ &wpa, &wap);
+ int rr = wr ? wr : svc_read_ap(vgpu,
+ wpa + (va & 0xfff),
+ wap == SVC_APERTURE_FB ?
+ SVC_APERTURE_FB :
+ SVC_APERTURE_SYS,
+ vb, len);
+ bool pl = !rr ? svc_method_stream_plausible(vb, len)
+ : false;
+
+ if (gsp_sema_dbg &&
+ svc_pushpg_fb_log < 64) {
+ svc_pushpg_fb_log++;
+ pr_info("sema-pushpg: h=0x%x va=0x%llx viawalk rc=%d pa=0x%llx plaus=%d\n",
+ ch->h_object, va,
+ wr ? wr : rr,
+ wpa + (va & 0xfff),
+ pl ? 1 : 0);
+ }
+ if (!wr && !rr && pl) {
+ memcpy(pb, vb, len);
+ svc.pushpg_fallback++;
+ ok = true;
+ if (gsp_sema_dbg &&
+ svc_pushpg_fb_log < 64) {
+ svc_pushpg_fb_log++;
+ pr_info("sema-pushpg: h=0x%x va=0x%llx viawalk ok pa=0x%llx\n",
+ ch->h_object, va,
+ wpa + (va & 0xfff));
+ }
+ }
+ kfree(vb);
+ if (!ok)
+ unreadable = true;
+ } else {
+ unreadable = true;
+ }
}
/*
* Still implausible (or
@@ -26975,19 +27274,43 @@ static void svc_scrub_pass(struct nv_vgpu_device *vgpu)
u32 put = 0;
u64 delta;
- if (!s || !s->userd_ok || !s->pa_ok || !s->entries)
+ if (!s)
+ return;
+ if (!s->userd_ok || !s->pa_ok || !s->entries) {
+ /* m112b: silent-return diagnostic (bounded per boot). */
+ if (s->log_budget < 8) {
+ s->log_budget++;
+ pr_info("sema-svc: scrub pass idle vgpu=%px slot=%d userd_ok=%d pa_ok=%d entries=%u gen=%u\n",
+ (void *)vgpu, (int)(s - svc_scrubs),
+ s->userd_ok, s->pa_ok, s->entries,
+ s->session_gen);
+ }
return;
+ }
if (svc_read_ap(vgpu, s->userd_pa + SVC_USERD_GP_PUT, s->userd_as,
&put, sizeof(put))) {
/* Retry through the alternate aperture (as registration did). */
if (svc_read_ap(vgpu, s->userd_pa + SVC_USERD_GP_PUT,
s->userd_as == SVC_APERTURE_FB ?
SVC_APERTURE_SYS : SVC_APERTURE_FB,
- &put, sizeof(put)))
+ &put, sizeof(put))) {
+ if (s->log_budget < 12) {
+ s->log_budget++;
+ pr_info("sema-svc: scrub pass read-fail userd=0x%llx as=%u\n",
+ s->userd_pa, s->userd_as);
+ }
return;
+ }
}
- if (put >= s->entries)
+ if (put >= s->entries) {
+ /* m112b: junk-translation diagnostic (bounded). */
+ if (s->log_budget < 12) {
+ s->log_budget++;
+ pr_info("sema-svc: scrub pass junk put=%u entries=%u userd=0x%llx\n",
+ put, s->entries, s->userd_pa);
+ }
return; /* junk translation; retry next pass */
+ }
if (!s->seeded) {
s->seeded = true;