summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_rm_emulation.c14
-rw-r--r--kernel/gsp_sema_service.c64
-rw-r--r--kernel/gsp_sema_service.h1
3 files changed, 79 insertions, 0 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index fc08b9d..7b7e230 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -3120,6 +3120,20 @@ static void gsp_rm_register_channel(struct gsp_emu_context *ctx, u32 h_object,
*/
if (desc.engine_type >= 1 && desc.engine_type <= 8)
desc.engine_type = 0;
+ /*
+ * r835: the channel's own address space (NV_CHANNEL_ALLOC_PARAMS:
+ * hContextShare @24, hVASpace @28 - confirmed by this struct's own
+ * known offsets: engineType @128 = 32 + 8 handles + 8 subdevice
+ * handles + 8 u64 userd offsets). Two clients map different objects
+ * at overlapping VAs (everyone's RM window sits at 0x1200xxxxx), so
+ * the global VA-keyed translation maps conflate them: the X server's
+ * ring VA resolved through the GL client's page tables (walk-probe:
+ * vas h=0xcaf00005 answered 0x120090000 with a zero page) and its
+ * push stream decoded as empty, wedging X exactly like the RC
+ * watchdog's ring. The service resolves a channel's VAs through this
+ * VAS first.
+ */
+ memcpy(&desc.h_vaspace, params + 28, 4);
memcpy(&desc.cid, params + GSPRM_CHAN_CID, 4);
memcpy(&desc.instance_pa, params + GSPRM_CHAN_INSTANCE_MEM, 8);
memcpy(&desc.userd_pa, params + GSPRM_CHAN_USERD_MEM, 8);
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
diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h
index 94faf82..63c7f82 100644
--- a/kernel/gsp_sema_service.h
+++ b/kernel/gsp_sema_service.h
@@ -31,6 +31,7 @@ struct sema_channel_desc {
u32 h_object;
u32 engine_type;
u32 cid; /* RM channel id (the doorbell token vector) */
+ u32 h_vaspace; /* r835: VAS handle the channel was allocated in */
u64 gpfifo_va;
u32 gpfifo_entries;
u64 userd_pa; /* NvA06FControl: GPGet @0x88, GPPut @0x8c */