summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-09 15:34:33 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-09 15:34:33 -0500
commitc38872182f2eb11660887ba73188d22a6b3835de (patch)
tree8d123cd79678c97890bb430779d25297652f17e1 /kernel/gsp_sema_service.c
parentad93b227526f42fa4ea7e529de883a9fa600c34d (diff)
downloadopen-iov-c38872182f2eb11660887ba73188d22a6b3835de.tar.gz
open-iov-c38872182f2eb11660887ba73188d22a6b3835de.zip
vgsp-sema: read a channel's push through the VAS it declared
Several VA spaces can map the same GPU VA. The push read's learned/pin chain is global over VASes, so the GL client's CE channel 0xcaf00012 (which pushes at 0x120000000) was answered with a zero page from another VAS and every entry was 'unreadable' while the channel's own VAS mapped the real method stream. Try the channel's declared VAS first; fall back to the existing source chain when it has no published directory or the walk misses.
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index e156339..c805fb5 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -24080,6 +24080,42 @@ static void svc_zrw_reset(u64 page_va)
}
}
+/*
+ * r1670: walk one VA through the VAS a channel declared at registration.
+ * The push-buffer read below uses this before the learned/pin chain: that
+ * chain is global over VASes, and several VASes map the same GPU VA (the GL
+ * client's CE channel 0xcaf00012 pushes at 0x120000000, which the learned
+ * map answered with a zero page from a different VAS while the channel's
+ * own VAS mapped the real method stream). Returns true on a walk hit.
+ */
+static bool svc_walk_vas_by_handle(struct nv_vgpu_device *vgpu, u32 h_vas,
+ u64 va, u64 *pa, int *ap)
+{
+ struct svc_vaspace local[SVC_MAX_VASPACES];
+ unsigned long flags;
+ int i, n = 0;
+
+ if (!h_vas)
+ return false;
+ spin_lock_irqsave(&svc.vas_lock, flags);
+ for (i = 0; i < SVC_MAX_VASPACES; i++)
+ if (svc.vas[i].valid && svc.vas[i].h_vaspace == h_vas)
+ local[n++] = svc.vas[i];
+ spin_unlock_irqrestore(&svc.vas_lock, flags);
+
+ for (i = 0; i < n; i++) {
+ int alt = local[i].ap == SVC_APERTURE_FB ?
+ SVC_APERTURE_SYS : SVC_APERTURE_FB;
+
+ if (!svc_gmmu_walk(vgpu, local[i].pdb, local[i].entries, va,
+ local[i].ap, pa, ap, false) ||
+ !svc_gmmu_walk(vgpu, local[i].pdb, local[i].entries, va,
+ alt, pa, ap, false))
+ return true;
+ }
+ return false;
+}
+
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)
@@ -24104,6 +24140,29 @@ static int svc_read_va_push_ex(struct nv_vgpu_device *vgpu,
have_win = !svc_pb_win_lookup(ch, page_va, &win_pa);
+ /*
+ * r1670: the VAS the channel declared at registration is the
+ * authority for its push buffer. The learned/pin chain below
+ * is global over VASes and can name a page from another
+ * address space that maps the same GPU VA.
+ */
+ if (ch->h_vaspace) {
+ u64 vpa = 0;
+ int vap = SVC_APERTURE_SYS;
+ u64 in_page = va & (SEMA_PAGE_SIZE - 1);
+
+ if (!svc_walk_vas_by_handle(vgpu, ch->h_vaspace,
+ page_va, &vpa, &vap) &&
+ vpa &&
+ !svc_read_ap(vgpu, vpa + in_page, vap, p,
+ chunk)) {
+ pa = vpa + in_page;
+ svc_read_last_src = 6;
+ svc_read_last_pa = pa;
+ done = true;
+ }
+ }
+
for (src = 0; src < 5 && !done; src++) {
bool via_ipin = false;
bool untrusted = false;