summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_sema_service.c39
1 files changed, 36 insertions, 3 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index b9cb40b..c46cbbb 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -2117,6 +2117,34 @@ static void svc_counter_release_apply(struct nv_vgpu_device *vgpu, u32 h,
}
/*
+ * Auto-register a GR channel's completion-counter slot from the observed
+ * layout, without waiting for a readable push: the client zips GR channels
+ * in ascending handle order with descending counter slots, so with n_gr
+ * channels the rank-r channel owns slot 0x20400fec0 + (n_gr-1-r)*0x10. Only
+ * a host-verified (pinned) translation is used, so the write target is the
+ * page the client actually polls. This lets the publish path advance every
+ * channel's counter even when some GR pushes are unreadable (observed: the
+ * lower ranks' 676-byte context-init pushes stayed unresolved while the
+ * other 13 channels' counters advanced, and the client timed out waiting).
+ */
+static void svc_counter_autoreg(struct svc_channel *ch, int n_gr)
+{
+ u64 va, pa = 0;
+ int ap = SVC_APERTURE_SYS;
+
+ if (ch->engine_type || ch->counter_pa || n_gr <= 0)
+ return;
+ if (ch->gr_index >= n_gr)
+ return;
+ va = 0x20400fec0ULL + (u64)(n_gr - 1 - ch->gr_index) * 0x10ULL;
+ if (svc_pin_lookup_any(va, &pa, &ap) || ap != SVC_APERTURE_SYS)
+ return;
+ ch->counter_pa = pa & ~0x3ULL;
+ pr_info("sema-chan: counter auto h=0x%x rank=%u pa=0x%llx (slot va=0x%llx)\n",
+ ch->h_object, ch->gr_index, ch->counter_pa, va);
+}
+
+/*
* Learn a GR channel's completion-counter guest PA from a release VA the
* push carried, so the publish path can advance the exact slot the client
* polls without any guest-side enumeration. Only a host-verified translation
@@ -3960,13 +3988,17 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
/* Only ever called from the service thread. */
static struct svc_channel local[SVC_MAX_CHANNELS];
unsigned long flags;
- int i, k, n = 0;
+ int i, k, n = 0, n_gr = 0;
bool stalled = false;
spin_lock_irqsave(&svc.chan_lock, flags);
- for (i = 0; i < SVC_MAX_CHANNELS; i++)
- if (svc.chan[i].valid)
+ for (i = 0; i < SVC_MAX_CHANNELS; i++) {
+ if (svc.chan[i].valid) {
local[n++] = svc.chan[i];
+ if (!svc.chan[i].engine_type)
+ n_gr++;
+ }
+ }
spin_unlock_irqrestore(&svc.chan_lock, flags);
for (i = 0; i < n; i++) {
@@ -4291,6 +4323,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
}
/* Advance the client-visible completion counter. */
+ svc_counter_autoreg(ch, n_gr);
svc_counter_publish(vgpu, ch, put);
spin_lock_irqsave(&svc.chan_lock, flags);