summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-30 12:41:59 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-30 12:41:59 -0400
commit0b0b86d88cd1ef499db6817e605fff888bc7a16c (patch)
treebd185f4e6e165c20ad200b4ed1d8f89a224de52c
parentb49301684fd59bea1143e6173522e4da7cc8a09b (diff)
downloadopen-iov-0b0b86d88cd1ef499db6817e605fff888bc7a16c.tar.gz
open-iov-0b0b86d88cd1ef499db6817e605fff888bc7a16c.zip
vgsp: FB USERD scan time-paced (1/25ms, cap 512) + pristine fallback for ring_pa==0 - fixes fresh-boot Xorg 10s DMA-init wall (2/2 boots green, DDX channel sub=3402, TWOD fills execute) - SESSION 153 r1014-r1015
-rw-r--r--kernel/gsp_sema_service.c114
1 files changed, 113 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 4ec75d6..bc04e25 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -735,6 +735,19 @@ struct svc_channel {
*/
u8 userd_scans;
/*
+ * SESSION 153-CONTINUED-37: time-paced re-run state for the FB USERD
+ * shape scan (r496b) and its pristine-block fallback. The old
+ * count-only cap spent every retry within ~64 ms of registration
+ * (pump pass cadence), while the X driver's pushbuffer test kicks its
+ * first GP_PUT hundreds of ms later and its VAS registers at ~1 s -
+ * so on unlucky timings the budget was gone before any candidate
+ * existed and the 10 s DMA test read GET=0 forever ("Failed to
+ * initialize DMA", r1013). One scan per 25 ms up to 512 keeps the
+ * discovery alive across the whole client window.
+ */
+ unsigned long fb_userd_scan_at; /* jiffies of the last scan */
+ u16 fb_userd_scan_n; /* scans spent since registration */
+ /*
* r828: the RC watchdog's notifier VA, captured from the class2d
* SET_NOTIFY_A/B methods on subchannel 3 and zeroed at the NOTIFY
* (see svc_notify2d_write). Survives the pass snapshot via the
@@ -18451,6 +18464,61 @@ static bool svc_gr_ram_userd_scan(struct nv_vgpu_device *vgpu,
u32 *put_out, u32 *get_out);
/*
+ * SESSION 153-CONTINUED-37: pristine-block USERD fallback for a GR channel
+ * whose ring does not translate yet.
+ *
+ * Measured (r1013 fresh boot): the X driver's pushbuffer-test channel
+ * (class 0xc46f, 8192 entries, VA 0x120090000) reports its USERD as the FB
+ * memdesc base 0x30000, but the guest's GPPut write lands in emulated vidmem
+ * at 0xa0000 - the params' base is relative to a client pool the emulation
+ * cannot see (same class of problem the r496b sweep solves once the ring
+ * resolves). The block is pristine in the test window: the only non-zero
+ * bytes in [0x0, 0x100) are the GP_PUT dword at +0x8c (GP_GET at +0x88 is
+ * still 0, because the driver zeroes it before the NOP test). When the
+ * channel's VAS page directory has not registered yet, the r496b sweep
+ * cannot run (it validates a hit by reading the ring entries the put
+ * claims), so this bounded shape scan keeps the discovery alive: pending
+ * only (get < put), pristine page, unclaimed by any other channel, then
+ * adopt it exactly like the ring-validated sweep does. The r496b sweep
+ * still runs later and may re-adopt a ring-validated block; both paths
+ * claim their latch, so a foreign channel cannot take it in between.
+ */
+static bool svc_fb_userd_pristine_scan(struct nv_vgpu_device *vgpu,
+ struct svc_channel *ch, u64 *off_out,
+ u32 *put_out, u32 *get_out)
+{
+ u8 *base = vgpu->bars[1].vaddr;
+ u64 lim, off;
+
+ if (!base || !ch->gpfifo_entries)
+ return false;
+ lim = min_t(u64, svc_fb_shadow_size(vgpu), 0x2000000ULL);
+ for (off = 0; off + 0x100 <= lim; off += 0x1000) {
+ u32 hp, hg;
+
+ memcpy(&hp, base + off + SVC_USERD_GP_PUT, 4);
+ if (!hp || hp > ch->gpfifo_entries)
+ continue;
+ memcpy(&hg, base + off + SVC_USERD_GP_GET, 4);
+ /* Only a posed kick (get < put) - an idle/stale block stays
+ * with its owner. */
+ if (hg >= hp)
+ continue;
+ if (memchr_inv(base + off, 0, SVC_USERD_GP_GET) ||
+ memchr_inv(base + off + SVC_USERD_GP_GET + 8, 0,
+ 0x100 - SVC_USERD_GP_GET - 8))
+ continue;
+ if (svc_fb_claim_foreign(vgpu, ch->h_object, 0, off))
+ continue;
+ *off_out = off;
+ *put_out = hp;
+ *get_out = hg;
+ return true;
+ }
+ return false;
+}
+
+/*
* Locate a channel's USERD. The allocation parameters carry an offset that is
* relative to a client pool the emulation cannot see, so it is only one
* candidate: for the combined GPFIFO+USERD allocations the control block sits
@@ -18774,7 +18842,11 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
* bounds the channel's life.
*/
if (!ch->engine_type && ring_pa &&
- ch->userd_scans < (ring_pa ? 64u : 8u)) {
+ ch->fb_userd_scan_n < 512 &&
+ (!ch->fb_userd_scan_at ||
+ time_after_eq(jiffies,
+ (unsigned long)ch->fb_userd_scan_at +
+ msecs_to_jiffies(25)))) {
u64 off, lim;
u8 *base = vgpu->bars[1].vaddr;
u64 best = 0, best_dist = ~0ULL;
@@ -18782,6 +18854,8 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
bool best_pending = false;
u32 gate_n = 0, vfail_n = 0;
+ ch->fb_userd_scan_at = jiffies;
+ ch->fb_userd_scan_n++;
ch->userd_scans++;
lim = min_t(u64, svc_fb_shadow_size(vgpu), 0x20000000ULL);
if (base && lim) {
@@ -18914,6 +18988,40 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
}
}
/*
+ * SESSION 153-CONTINUED-37: the channel's ring VA does not translate
+ * yet (the client's VAS page directory registers ~1 s after channel
+ * creation; until then svc_lookup cannot resolve it and the
+ * ring-validated r496b sweep above never runs). The driver's DMA
+ * test only needs the block it is polling: a freshly kicked pristine
+ * FB block (see svc_fb_userd_pristine_scan). Adopt it so the pump
+ * starts iterating entries as soon as the ring walk lands, inside
+ * the driver's 10 s window.
+ */
+ if (!ch->engine_type && !ring_pa &&
+ ch->fb_userd_scan_n < 512 &&
+ (!ch->fb_userd_scan_at ||
+ time_after_eq(jiffies,
+ (unsigned long)ch->fb_userd_scan_at +
+ msecs_to_jiffies(25)))) {
+ u64 off = 0;
+ u32 p = 0, g = 0;
+
+ ch->fb_userd_scan_at = jiffies;
+ ch->fb_userd_scan_n++;
+ if (svc_fb_userd_pristine_scan(vgpu, ch, &off, &p, &g)) {
+ ch->userd_pa = off;
+ ch->userd_as = SVC_APERTURE_FB;
+ ch->userd_ok = true;
+ svc_fb_claim_add(ch->h_object, 0, off);
+ *put = p;
+ *get = g;
+ pr_info("sema-chan: GR USERD h=0x%x rank=%u found by pristine-FB scan at fb 0x%llx (put=%u get=%u; ring 0x%llx not translated yet)\n",
+ ch->h_object, ch->gr_index, off, p, g,
+ ch->gpfifo_va);
+ return 0;
+ }
+ }
+ /*
* SESSION 153-CONT-34: last resort for the GL client family - retry the
* registered offset as a BAR0-shadow USERD. Every other source (layout,
* ring-derived, RAM scan, FB sweep) has already missed the block whose
@@ -35213,6 +35321,10 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc.chan[k].gr_kick_ring_reval_at =
ch->gr_kick_ring_reval_at;
svc.chan[k].userd_scans = ch->userd_scans;
+ svc.chan[k].fb_userd_scan_at =
+ ch->fb_userd_scan_at;
+ svc.chan[k].fb_userd_scan_n =
+ ch->fb_userd_scan_n;
svc.chan[k].notify2d_va = ch->notify2d_va;
svc.chan[k].zero_held = ch->zero_held;
svc.chan[k].userd_reg = ch->userd_reg;