summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-09 15:35:33 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-09 15:35:33 -0400
commitb2fdd56bfa51d4a1dbc5fe91adb7b82d15e02c00 (patch)
treea6a0970b08d06db6c3c4464380deb4a88d841c7c
parent8ca727779d41f5de05991b3f9fb1b1ebf0c28db4 (diff)
downloadopen-iov-b2fdd56bfa51d4a1dbc5fe91adb7b82d15e02c00.tar.gz
open-iov-b2fdd56bfa51d4a1dbc5fe91adb7b82d15e02c00.zip
vgsp-sema: CE USERD layout-only + deferred FB sweep diag (ISSUE-0002)
r46 evidence: in a second session the CE rank0 layout probe at ring+0x10000 read a transient incoherent pair (-EINVAL) at discovery and the old candidate list immediately latched the stale registered pool-relative offset (another rank's previous-session USERD, frozen 1/1), hiding every later GP_PUT. For CE channels enforce the ring-derived layout block only, retry until it reads coherent, and never fall back to the registered/neighbour candidates. A bounded (+3s, +33s) FB sweep logs the live put/get block when the layout never becomes coherent.
-rw-r--r--kernel/gsp_sema_service.c211
1 files changed, 190 insertions, 21 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 4cc1624..43a8d62 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -4696,6 +4696,38 @@ static u64 svc_rel_va_seen;
static u32 svc_rel_count;
static u32 svc_dbg_streams;
static u32 svc_chan_put_log;
+/*
+ * ISSUE-0002 (r46 diag): bounded per-session log for the CE USERD discovery
+ * decision (svc_chan_userd). Budgets reset in svc_session_flush; 3 attempts
+ * per rank, 36 lines per session, so every CE channel of the second client
+ * gets logged without a log storm.
+ */
+static u32 svc_userd_dbg;
+static u32 svc_userd_dbg_ch[32];
+/*
+ * ISSUE-0002 (r47): deferred FB sweep for a CE channel whose layout USERD
+ * probe fails at discovery. Session/reset-scoped, scheduled on the first
+ * failure (+3 s) and re-run once more (+30 s, after the client's follow-up
+ * pushes have landed) to name where the live put/get block actually is.
+ */
+static u64 svc_userd_sweep_at[32];
+static u32 svc_userd_sweep_n[32];
+static u32 svc_userd_sweep_log;
+
+/*
+ * Schedule the first deferred sweep for a CE rank whose layout USERD probe
+ * did not accept. Only once: the pump re-arms the second sweep after the
+ * first fires (svc_userd_sweep_n tracks the count).
+ */
+static void svc_userd_sweep_sched(struct svc_channel *ch)
+{
+ if (ch->ce_index >= 32)
+ return;
+ if (svc_userd_sweep_n[ch->ce_index] ||
+ svc_userd_sweep_at[ch->ce_index])
+ return;
+ svc_userd_sweep_at[ch->ce_index] = jiffies + 3 * HZ;
+}
/*
* Ring of recent GRCE inline-write destinations and their payload bytes
@@ -6714,6 +6746,11 @@ static void svc_session_flush(void)
svc.gpfifo_entry_log = 0;
svc_dbg_streams = 0;
svc_chan_put_log = 0;
+ svc_userd_dbg = 0;
+ memset(svc_userd_dbg_ch, 0, sizeof(svc_userd_dbg_ch));
+ svc_userd_sweep_log = 0;
+ memset(svc_userd_sweep_at, 0, sizeof(svc_userd_sweep_at));
+ memset(svc_userd_sweep_n, 0, sizeof(svc_userd_sweep_n));
memset(svc_hot, 0, sizeof(svc_hot));
memset(svc_retry_q, 0, sizeof(svc_retry_q));
memset(svc_pool_pa, 0, sizeof(svc_pool_pa));
@@ -7680,12 +7717,12 @@ static int svc_userd_probe(struct nv_vgpu_device *vgpu, u64 pa, u32 as,
return -ENOENT;
if (svc_read_ap(vgpu, pa + SVC_USERD_GP_GET, as, &g, sizeof(g)))
return -ENOENT;
+ *put = p;
+ *get = g;
if (p > entries || g > p)
return -EINVAL;
if (!p && !g)
- return -EAGAIN; /* plausible but idle: keep looking */
- *put = p;
- *get = g;
+ return -EAGAIN; /* plausible but idle: callers decide */
return 0;
}
@@ -7707,7 +7744,7 @@ static int svc_userd_probe(struct nv_vgpu_device *vgpu, u64 pa, u32 as,
* failed probe (the values must still read as a coherent put/get pair).
*/
static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
- u64 ring_pa, int ring_ap, u32 *put, u32 *get)
+ u64 ring_pa, int ring_ap, u32 *put, u32 *get, int rrc)
{
u64 cand[8];
u32 as[8], nc = 0, i;
@@ -7736,11 +7773,13 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
*/
if (ring_pa && ch->engine_type != 0) {
u8 e[SVC_GPFIFO_ENTRY_SIZE];
- u32 e0, e1, len;
- u64 va;
+ u32 e0 = 0, e1 = 0, len = 0, p = 0, g = 0;
+ u64 va = 0;
bool ring_ok = false;
+ int irc = -1, rc = -1;
if (!svc_read_ap(vgpu, ring_pa, ring_ap, e, sizeof(e))) {
+ irc = 0;
memcpy(&e0, e, 4);
memcpy(&e1, e + 4, 4);
va = ((u64)(e1 & 0xff) << 32) |
@@ -7750,21 +7789,60 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
va >= 0x120000000ULL && va < 0x121000000ULL &&
len >= 4 && len <= 0x10000;
}
- if (ring_ok) {
- u32 p = 0, g = 0;
- int rc = svc_userd_probe(vgpu, ring_pa + 0x10000,
- ring_ap, ch->gpfifo_entries,
- &p, &g);
-
- if (rc == 0 || rc == -EAGAIN) {
- ch->userd_pa = ring_pa + 0x10000;
- ch->userd_as = ring_ap;
- ch->userd_ok = true;
- *put = p;
- *get = g;
- return 0;
- }
+ if (ring_ok)
+ rc = svc_userd_probe(vgpu, ring_pa + 0x10000,
+ ring_ap, ch->gpfifo_entries,
+ &p, &g);
+ /*
+ * ISSUE-0002 (r46 diag): name the exact failing check on the
+ * CE discovery decision. Three lines per rank, 36 per session.
+ */
+ if (gsp_sema_dbg && ch->ce_index < 32 &&
+ svc_userd_dbg_ch[ch->ce_index] < 3 && svc_userd_dbg < 36) {
+ svc_userd_dbg_ch[ch->ce_index]++;
+ svc_userd_dbg++;
+ pr_info("sema-userd: h=0x%x rank=%u rrc=%d rpa=0x%llx rap=%d irc=%d e0=0x%x e1=0x%x va=0x%llx len=%u ring_ok=%d prc=%d p=%u g=%u lat=0\n",
+ ch->h_object, ch->ce_index, rrc, ring_pa,
+ ring_ap, irc, e0, e1, va, len, ring_ok ? 1 : 0,
+ rc, p, g);
+ }
+ if (ring_ok && (rc == 0 || rc == -EAGAIN)) {
+ ch->userd_pa = ring_pa + 0x10000;
+ ch->userd_as = ring_ap;
+ ch->userd_ok = true;
+ *put = p;
+ *get = g;
+ if (ch->ce_index < 32)
+ svc_userd_sweep_at[ch->ce_index] = 0;
+ return 0;
}
+ } else if (ch->engine_type != 0) {
+ /* No ring translation this pass: log once per bounded budget. */
+ if (gsp_sema_dbg && ch->ce_index < 32 &&
+ svc_userd_dbg_ch[ch->ce_index] < 3 && svc_userd_dbg < 36) {
+ svc_userd_dbg_ch[ch->ce_index]++;
+ svc_userd_dbg++;
+ pr_info("sema-userd: h=0x%x rank=%u rrc=%d rpa=0x%llx rap=%d irc=-2 norrng\n",
+ ch->h_object, ch->ce_index, rrc, ring_pa,
+ ring_ap);
+ }
+ }
+
+ /*
+ * ISSUE-0002 (r47): for CE channels the ring-derived layout block is
+ * authoritative. Never fall back to the registered pool-relative
+ * offset or the neighbour candidates: r46 proved that when the layout
+ * probe reads a transient incoherent pair at discovery (session 2
+ * rank0: -EINVAL while the guest was (re)initialising the block) the
+ * old list immediately latched the stale registered block (0xf0000 =
+ * the previous session's rank3 USERD) whose frozen 1/1 then hid every
+ * later GP_PUT. Retry on the next pass instead; arm the deferred
+ * sweep so the live block can be located if it never turns coherent
+ * at the layout offset.
+ */
+ if (ch->engine_type != 0) {
+ svc_userd_sweep_sched(ch);
+ return -ENOENT;
}
if (ring_pa) {
@@ -7798,6 +7876,17 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
continue;
if (!svc_userd_probe(vgpu, cand[i], as[i], ch->gpfifo_entries,
put, get)) {
+ /* ISSUE-0002 r46: name a fallback latch (CE wrong block). */
+ if (gsp_sema_dbg && ch->engine_type &&
+ ch->ce_index < 32 &&
+ svc_userd_dbg_ch[ch->ce_index] < 3 &&
+ svc_userd_dbg < 36) {
+ svc_userd_dbg_ch[ch->ce_index]++;
+ svc_userd_dbg++;
+ pr_info("sema-userd: h=0x%x rank=%u fallback cand=0x%llx as=%u i=%u/%u put=%u get=%u\n",
+ ch->h_object, ch->ce_index, cand[i],
+ as[i], i, nc, *put, *get);
+ }
ch->userd_pa = cand[i];
ch->userd_as = as[i];
ch->userd_ok = true;
@@ -12054,6 +12143,66 @@ static void svc_entry_outcome(const char *what, const struct svc_channel *ch,
ch->expected_sem_payload, ch->unread_until ? 1 : 0);
}
+/*
+ * ISSUE-0002 (r47 diag): deferred scan of the emulated vidmem for the LIVE
+ * CE USERD block of a channel whose ring-derived layout probe never turned
+ * coherent. Reads the FB backing directly (same thread as the pump), logs
+ * the layout probe result, the ring's entry0, and the first coherent
+ * put/get blocks with put >= 2 (the live block after the client's follow-up
+ * push; stale blocks are frozen at 1/1 or the previous session's values).
+ * Bounded per session; diagnostic only.
+ */
+static void svc_userd_sweep(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
+ u64 ring_pa, int ring_ap, int rrc)
+{
+ u8 *fb = (u8 *)vgpu->bars[1].vaddr;
+ u32 p = 0, g = 0, off, hi = 0, lo = 0;
+ int rc = -1;
+
+ if (!gsp_sema_dbg || !fb || !ch->gpfifo_entries || ch->ce_index >= 32)
+ return;
+ if (svc_userd_sweep_log >= 90)
+ return;
+ svc_userd_sweep_log++;
+
+ if (ring_pa)
+ rc = svc_userd_probe(vgpu, ring_pa + 0x10000, ring_ap,
+ ch->gpfifo_entries, &p, &g);
+ pr_info("sema-userd-sweep: h=0x%x rank=%u n=%u rrc=%d rpa=0x%llx rap=%d rc=%d p=%u g=%u\n",
+ ch->h_object, ch->ce_index, svc_userd_sweep_n[ch->ce_index],
+ rrc, ring_pa, ring_ap, rc, p, g);
+ if (ring_pa) {
+ u8 e[8];
+ u32 e0 = 0, e1 = 0;
+
+ if (!svc_read_ap(vgpu, ring_pa, ring_ap, e, sizeof(e))) {
+ memcpy(&e0, e, 4);
+ memcpy(&e1, e + 4, 4);
+ }
+ pr_info("sema-userd-sweep: h=0x%x e0=0x%x e1=0x%x\n",
+ ch->h_object, e0, e1);
+ }
+ for (off = 0x80000; off + 8 <= vgpu->bars[1].size && off < 0x200000;
+ off += 0x1000) {
+ u32 w0, w1;
+
+ memcpy(&w0, fb + off, 4);
+ memcpy(&w1, fb + off + 4, 4);
+ if (!w0 || w0 > ch->gpfifo_entries || w1 > w0)
+ continue;
+ if (w0 >= 2) {
+ if (hi < 4)
+ pr_info("sema-userd-sweep: h=0x%x hit2 off=0x%x w0=%u w1=%u\n",
+ ch->h_object, off, w0, w1);
+ hi++;
+ } else {
+ lo++;
+ }
+ }
+ pr_info("sema-userd-sweep: h=0x%x done hi=%u lo=%u\n",
+ ch->h_object, hi, lo);
+}
+
static void svc_pump_channels(struct nv_vgpu_device *vgpu)
{
/* Only ever called from the service thread. */
@@ -12192,9 +12341,29 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
if (!rrc)
svc_pb_pair(vgpu, ch);
+ /*
+ * ISSUE-0002 (r47 diag): run the deferred CE USERD sweep for a
+ * channel whose layout probe never accepted. The second sweep
+ * is armed here, 27 s after the first, so it lands after the
+ * client's follow-up pushes.
+ */
+ if (ch->engine_type && ch->ce_index < 32 && !ch->userd_ok &&
+ svc_userd_sweep_at[ch->ce_index] &&
+ time_after_eq(jiffies,
+ (unsigned long)svc_userd_sweep_at[ch->ce_index])) {
+ svc_userd_sweep_at[ch->ce_index] = 0;
+ svc_userd_sweep(vgpu, ch, rrc ? 0 : ring_pa,
+ rrc ? -1 : ring_ap, rrc);
+ svc_userd_sweep_n[ch->ce_index]++;
+ if (svc_userd_sweep_n[ch->ce_index] < 2)
+ svc_userd_sweep_at[ch->ce_index] =
+ jiffies + 27 * HZ;
+ }
+
if (!ch->userd_ok) {
if (svc_chan_userd(vgpu, ch, rrc ? 0 : ring_pa,
- rrc ? -1 : ring_ap, &put, &get)) {
+ rrc ? -1 : ring_ap, &put, &get,
+ rrc)) {
/*
* The channel's work cannot be run (USERD not
* found): its pushes stay pending, so the release