diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_sema_service.c | 82 |
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; |
