summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_sema_service.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index e16deb2..ca848c6 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -1293,6 +1293,7 @@ struct sema_svc {
* (pin/walk disagreement; the
* r538 init-stall class) */
u64 pool_dual_log; /* r539 fan-out log budget */
+ u64 pool_tracker_log; /* r1642 tracker-slot budget */
u64 pool_residue; /* fresh-channel first releases whose
* pool word read far ahead of the
* payload (previous session's
@@ -5567,6 +5568,56 @@ static bool svc_wait_pend_release(u64 va);
static bool svc_gr_rel_match(u64 va, u32 *payload);
static bool svc_gr_rel_inflight(u64 va, u32 *payload);
+/*
+ * r1642: UVM's channel-pool semaphore map reserves slot 0 for the pool
+ * release; each channel's own tracking semaphore lives at map_base +
+ * 4*(rank+1). Gdbstub proof on the guest: the rank-0 UVM channel's
+ * uvm_gpu_tracking_semaphore polled map_base+4 while its push released
+ * map_base+0, and writing the payload into map_base+4 cleared the
+ * uvm_push_end_and_wait spin. When a CE channel releases the pool slot,
+ * apply the same forward-only value to its tracker slot as well.
+ */
+#define SVC_UVM_POOL_MAP_BASE 0x121000000ULL
+static void svc_pool_tracker_apply(struct nv_vgpu_device *vgpu, u32 h,
+ u64 va, u32 val)
+{
+ u64 tva, addr = 0;
+ const char *src = NULL;
+ int ap = 0;
+ u32 cur = 0, back = 0;
+ int i;
+
+ if (va < SVC_UVM_POOL_MAP_BASE ||
+ va >= SVC_UVM_POOL_MAP_BASE + SEMA_PAGE_SIZE)
+ return;
+ for (i = 0; i < SVC_MAX_CHANNELS; i++)
+ if (svc.chan[i].valid && svc.chan[i].h_object == h &&
+ svc.chan[i].engine_type)
+ break;
+ if (i == SVC_MAX_CHANNELS)
+ return;
+ tva = SVC_UVM_POOL_MAP_BASE + 4ULL *
+ ((u64)svc.chan[i].ce_index + 1);
+ if (tva == va)
+ return;
+ if (svc_pool_pa_resolve(vgpu, h, tva, &addr, &ap, &src))
+ return;
+ if (svc_read_ap(vgpu, addr, svc_ap_of(ap), &cur, sizeof(cur)))
+ return;
+ if (cur >= val)
+ return;
+ if (svc_write_ap(vgpu, addr, svc_ap_of(ap), &val, sizeof(val)))
+ return;
+ if (svc_read_ap(vgpu, addr, svc_ap_of(ap), &back, sizeof(back)) ||
+ back != val)
+ return;
+ if (svc.pool_tracker_log < 64) {
+ svc.pool_tracker_log++;
+ pr_info("sema-svc: pool-tracker-wr ch=0x%x rank=%u va=0x%llx pa=0x%llx val=%u\n",
+ h, svc.chan[i].ce_index, tva, addr, val);
+ }
+}
+
static int svc_sem_write(struct nv_vgpu_device *vgpu, u32 h, u64 va, u32 val)
{
u64 addr = 0, old_addr;
@@ -5677,6 +5728,7 @@ static int svc_sem_write(struct nv_vgpu_device *vgpu, u32 h, u64 va, u32 val)
svc_pool_wr_note(h, va, addr, src, cur, val, "ok");
svc_pool_alt_apply(vgpu, h, va, val);
svc_pool_boot_fanout(vgpu, h, va, val);
+ svc_pool_tracker_apply(vgpu, h, va, val);
}
return 0;
}
@@ -5717,6 +5769,7 @@ static int svc_sem_write(struct nv_vgpu_device *vgpu, u32 h, u64 va, u32 val)
"advisory");
svc_pool_alt_apply(vgpu, h, va, val);
svc_pool_boot_fanout(vgpu, h, va, val);
+ svc_pool_tracker_apply(vgpu, h, va, val);
}
return 0; /* the original write landed; read-back is advisory */
}