summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_sema_service.c82
1 files changed, 67 insertions, 15 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 5e887f1..8d223d8 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -389,6 +389,19 @@ static u32 svc_pb_n;
static u32 svc_ring_n;
static u8 svc_pb_passes;
static u64 svc_pb_last;
+/*
+ * Pass budget for svc_pb_discover: stop after SVC_PB_IDLE_PASSES
+ * consecutive passes with no new base (the discovery has drained), with a
+ * hard cap so a channel that has no push-buffer base page cannot keep the
+ * pass running for the boot. The old code stopped at a flat 12 passes,
+ * which could retire discovery before a later channel/session's base
+ * appeared (ISSUE-0001 durable direction).
+ */
+#define SVC_PB_IDLE_PASSES 6
+#define SVC_PB_PASS_MAX 48
+static u32 svc_pb_idle; /* consecutive passes with no new base */
+static u32 svc_pb_last_n; /* bases before the active pass */
+static unsigned long svc_pb_done; /* CE ranks whose push buffer is pinned */
static bool svc_pb_first_push(const u8 *buf)
{
@@ -6534,30 +6547,67 @@ static void svc_pb_discover(struct nv_vgpu_device *vgpu)
unsigned long flags;
u8 *buf;
u64 gpa;
- bool ce = false;
+ bool ce = false, need = false;
int i;
- if (svc_pb_passes >= 12 || svc_pb_n >= SVC_PB_MAX)
- return;
- if (time_before(jiffies, (unsigned long)svc_pb_last + 3 * HZ))
- return;
-
spin_lock_irqsave(&svc.chan_lock, flags);
- for (i = 0; i < SVC_MAX_CHANNELS; i++)
- if (svc.chan[i].valid && svc.chan[i].engine_type) {
- ce = true;
- break;
- }
+ for (i = 0; i < SVC_MAX_CHANNELS; i++) {
+ u32 slot, k;
+ bool have = false;
+
+ if (!svc.chan[i].valid || !svc.chan[i].engine_type)
+ continue;
+ ce = true;
+ if (svc.chan[i].ce_index >= 32)
+ continue;
+ if (test_bit(svc.chan[i].ce_index, &svc_pb_done))
+ continue;
+ /*
+ * "Need" means no content-discovered base exists for this
+ * channel's release slot yet. Once the base is recorded the
+ * pass can idle out even if the pump has not paired the
+ * window; pairing is a pump concern, not a discovery one.
+ */
+ slot = 4 * svc.chan[i].ce_index;
+ for (k = 0; k < svc_pb_n; k++)
+ if (svc_pb[k].slot == slot) {
+ have = true;
+ break;
+ }
+ if (!have)
+ need = true;
+ }
spin_unlock_irqrestore(&svc.chan_lock, flags);
if (!ce)
return;
+ /*
+ * Discovery stays alive while it is still finding bases or while a
+ * registered CE channel has no paired base (ISSUE-0001 durable
+ * direction). The old flat 12-pass budget stopped the pass even when
+ * a channel had appeared (or reappeared with a new client session)
+ * after the budget was spent, so its push-buffer base was never
+ * paired and every push depended on the slower per-page rescue and
+ * watcher pins. Stop only after SVC_PB_IDLE_PASSES consecutive
+ * passes with no new base AND no unpaired channel, with a hard cap
+ * so a channel that genuinely has no base page cannot scan forever.
+ * The 3 s rate limit and the chunked walk keep the service thread
+ * responsive.
+ */
+ if (svc_pb_n >= SVC_PB_MAX || svc_pb_passes >= SVC_PB_PASS_MAX)
+ return;
+ if (svc_pb_idle >= SVC_PB_IDLE_PASSES && !need)
+ return;
+ if (time_before(jiffies, (unsigned long)svc_pb_last + 3 * HZ))
+ return;
+
buf = kmalloc(SVC_SCAN_CHUNK, GFP_KERNEL);
if (!buf)
return;
svc_pb_passes++;
svc_pb_last = jiffies;
+ svc_pb_last_n = svc_pb_n;
for (gpa = 0; gpa < SEMA_PA_MAX; gpa += SVC_SCAN_CHUNK) {
u32 o;
@@ -6567,8 +6617,12 @@ static void svc_pb_discover(struct nv_vgpu_device *vgpu)
svc_pb_note(vgpu, buf + o, gpa + o);
}
kfree(buf);
- pr_info("sema-svc: push-buffer discovery pass %u done (%u bases, ring %u)\n",
- svc_pb_passes, svc_pb_n, svc_ring_n);
+ if (svc_pb_n > svc_pb_last_n)
+ svc_pb_idle = 0;
+ else
+ svc_pb_idle++;
+ pr_info("sema-svc: push-buffer discovery pass %u done (%u bases, ring %u, idle %u)\n",
+ svc_pb_passes, svc_pb_n, svc_ring_n, svc_pb_idle);
}
/*
@@ -7587,8 +7641,6 @@ static void svc_ring_autopin(struct nv_vgpu_device *vgpu,
* carries the push-buffer VA, the base page was found by content and its
* release names the channel's slot (4 bytes per rank).
*/
-static unsigned long svc_pb_done; /* CE ranks whose push buffer is pinned */
-
static void svc_pb_pair(struct nv_vgpu_device *vgpu, struct svc_channel *ch)
{
u64 hit_pa = 0, va = 0;