summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-27 07:06:12 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-27 07:06:12 -0400
commit38ba1e2d7d579c2467dfa10daca16cdbd6579089 (patch)
tree260d5daf67386aeae61501c5e4690e918ee9e310 /kernel/gsp_sema_service.c
parent42c9626b19037f45d7be9e1c228ec4376b0f29cc (diff)
downloadopen-iov-38ba1e2d7d579c2467dfa10daca16cdbd6579089.tar.gz
open-iov-38ba1e2d7d579c2467dfa10daca16cdbd6579089.zip
vgsp: channel-scoped VA resolution via the channel's own VAS (r835)
Every RM client maps different objects at the same numeric VAs (all clients' windows sit at 0x1200xxxxx), so the global VA-keyed pin/lat/map layers conflate them across clients. Live walk_probe evidence (r834): the X server's ring VA 0x120090000 resolved through the GL client's page tables (vas h=0xcaf00005 -> a zero page) while the X client's own VAS (vas h=0x10005) holds the real page (pa=0x1294fa000). That conflation is what wedged the X server's readback wait and starved the RC watchdog's ring (its pushes decoded as empty). * Parse NV_CHANNEL_ALLOC_PARAMS.hVASpace (@28; layout confirmed by the struct's own known offsets) at channel registration and carry it on svc_channel. * svc_chanvas_lookup: resolve a VA through the serviced channel's own VAS page tables first (svc_cur_vas, refreshed per channel turn and in the decode path). The hook sits at the head of svc_lookup_trusted, so ring, push, release and notifier resolution all inherit it; a failed walk falls through to the old chain unchanged. Live r835: X's XShmGetImage readback, previously never completing, returned after its long wait and a frame reached the kvmfr BAR (first frame content still black and readback latency still ~87 s; the guest-side fbcopy_pub framebuffer reader tool is added for the direct-VRAM capture path, find/pub/test modes).
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 5307bdd..f6ad3b2 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -205,6 +205,18 @@ struct svc_channel {
u32 h_object;
u32 engine_type;
u32 cid; /* RM channel id (doorbell token vector) */
+ u32 h_vaspace; /* r835: the client VAS this channel was
+ * allocated in (NV_CHANNEL_ALLOC_PARAMS.
+ * hVASpace). Channel-scoped VA resolution
+ * consults this VAS's page tables FIRST:
+ * every client's RM window sits at the same
+ * VAs (0x1200xxxxx) and the global VA-keyed
+ * maps conflate them - the X server's ring
+ * VA resolved through the GL client's page
+ * tables (walk-probe vas h=0xcaf00005
+ * answered 0x120090000) and its push stream
+ * decoded as zero pages, wedging X the same
+ * way the RC watchdog's ring was starved. */
u8 ce_index; /* rank among the live CE channels (creation order) */
u8 gr_index; /* rank among the live GR channels (creation order) */
u64 gpfifo_va;
@@ -1572,6 +1584,7 @@ void gsp_sema_service_channel_add(const struct sema_channel_desc *desc)
ch->h_object = desc->h_object;
ch->engine_type = desc->engine_type;
ch->cid = desc->cid;
+ ch->h_vaspace = desc->h_vaspace;
ch->gpfifo_va = desc->gpfifo_va;
ch->gpfifo_entries = desc->gpfifo_entries;
ch->userd_pa = desc->userd_pa;
@@ -3570,11 +3583,56 @@ static bool svc_resolve_in_progress(u64 va)
* VA above the window base, including sysmem-backed VAs, so callers that must
* not act on a guess (push execution) use this variant.
*/
+/*
+ * r835: the VAS handle of the channel currently being serviced (0 = none).
+ * Channel-scoped VA resolution consults this VAS's page tables FIRST: the
+ * global pin/lat/map layers are VA-keyed and every client's RM window sits
+ * at the same VAs (0x1200xxxxx), so a lookup outside the owning client's
+ * page tables can answer ANOTHER client's page - the X server's ring
+ * resolved to the GL client's (zero) page and its pushes decoded empty,
+ * wedging X's readback wait exactly like the RC watchdog's ring starvation.
+ */
+static u32 svc_cur_vas;
+
+static int svc_chanvas_lookup(struct nv_vgpu_device *vgpu, u64 va, u64 *addr,
+ int *ap)
+{
+ int i;
+
+ if (!svc_cur_vas)
+ return -ENOENT;
+ for (i = 0; i < SVC_MAX_VASPACES; i++) {
+ u64 pa = 0;
+ int a = SVC_APERTURE_SYS;
+
+ if (!svc.vas[i].valid ||
+ svc.vas[i].h_vaspace != svc_cur_vas)
+ continue;
+ if (svc_gmmu_walk(vgpu, svc.vas[i].pdb, svc.vas[i].entries,
+ va & ~(u64)(SEMA_PAGE_SIZE - 1),
+ svc.vas[i].ap, &pa, &a, false))
+ continue;
+ *addr = pa + (va & (SEMA_PAGE_SIZE - 1));
+ *ap = a;
+ return 0;
+ }
+ return -ENOENT;
+}
+
static int svc_lookup_trusted(struct nv_vgpu_device *vgpu, u64 va, u64 *addr,
int *ap)
{
u64 pa = 0;
+ /*
+ * r835: the decoded channel's own page tables answer first. When a
+ * channel is being serviced (svc_cur_vas set) its VAS is the only
+ * authoritative source for its VAs; the VA-keyed layers below may
+ * hold another client's pages for the same numeric VA. A failed
+ * walk falls through to the old chain unchanged.
+ */
+ if (!svc_chanvas_lookup(vgpu, va, addr, ap))
+ return 0;
if (!svc_pin_lookup_any(va, addr, ap)) {
return 0;
}
@@ -10839,6 +10897,8 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
* and the matmul r322 starved/hung note).
*/
svc.cur_ch = ch->h_object;
+ /* r835: decode-scoped VAS for channel-first VA resolution. */
+ svc_cur_vas = ch->h_vaspace;
/*
* r34x: the acquire-wait capture is PER RING ENTRY. It used to be
* reset only at SET_OBJECT, so a decode pass over a later entry (or
@@ -27215,6 +27275,10 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
get_before = ch->last_get;
applied_before = svc.releases_applied;
+ /* r835: this channel's VAS answers its VAs first (see
+ * svc_chanvas_lookup). Refreshed per channel turn; a channel
+ * without a known VAS clears it back to the old chain. */
+ svc_cur_vas = ch->h_vaspace;
/*
* C4 (GAP-1 H1): the GR walk witness - does put advance, and