diff options
| -rw-r--r-- | kernel/gsp_sema_service.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 127f995..0f89f5a 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -1615,6 +1615,7 @@ static u32 svc_cand_ovw_log; /* C9: candidate overwrite witness */ static u32 svc_inline_recs_log; /* C10: inline-recs digest witness */ static u32 svc_gr_await_log; /* r351: launch-held-for-trust witness */ static u32 svc_gr_retry_log; /* r351: retry-forward/proceed witness */ +static bool svc_hold_bypass(void); /* r563: stall self-heal forward decl */ /* * r551: releases DELIVERED by the opdef hold-expiry paths (flush/sweep) are @@ -22670,6 +22671,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) if (svc.op_tr_pending && !svc_gr_hold_bound_expired(ch, svc_gr_launch_va(ch)) && + !svc_hold_bypass() && svc_opdef_hold(vgpu, ch, (u32)idx, va)) { @@ -22829,7 +22831,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) ch); if (fwd_guest_queued) { svc.fwd_gr_defer++; - } else if (!svc_gr_hold_bound_expired(ch, + } else if (!svc_hold_bypass() && + !svc_gr_hold_bound_expired(ch, svc_gr_launch_va(ch)) && (ch->gr_hold_idx != (u32)idx || time_before(jiffies, @@ -22923,6 +22926,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) if (!fwd_guest_queued && !ch->engine_type && svc_gr_data_stalled && + !svc_hold_bypass() && !svc_gr_hold_bound_expired(ch, svc_gr_launch_va(ch)) && (ch->gr_hold_idx != (u32)idx || @@ -23231,7 +23235,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) time_before(jiffies, ch->gr_nocap_since + msecs_to_jiffies( - gsp_sema_gr_nocap_hold_ms))) { + gsp_sema_gr_nocap_hold_ms)) && + !svc_hold_bypass()) { /* Force a fresh capture on * the retry: a replay decode * would suppress it. */ @@ -24977,6 +24982,31 @@ static unsigned long svc_stall_watch_last; static u64 svc_stall_watch_done; static u32 svc_stall_watch_dumps; +/* + * r563: stall-watchdog self-heal. The r562 STALL-DUMP shape (pump alive, + * no entry consumed for 20 s, held/opdef counters frozen) has been closed + * one hole at a time (r548..r558), but every remaining interaction hole + * has the same end state: some hold condition keeps winning and the walk + * breaks on the same entry forever. When the watchdog fires, arm a small + * budget of forced consumes: the next hold decisions that would otherwise + * park an entry are bypassed, the entry is consumed with its withheld + * releases applied forward-only (and the GR QMD completion authored by the + * existing tail), and the client's wait advances. Bounded by the dump + * cadence (<= 4 per boot) and by the budget (4 hold bypasses per arming), + * so a healthy boot never sees it and a stalled one cannot livelock. + */ +static u32 svc_force_consume; + +static inline bool svc_hold_bypass(void) +{ + if (!svc_force_consume) + return false; + svc_force_consume--; + pr_info_ratelimited("vgsp-sema: STALL-HEAL: hold bypassed (forced consume, budget left %u)\n", + svc_force_consume); + return true; +} + static void svc_stall_watch_dump(void) { u32 i; @@ -25035,6 +25065,8 @@ static void svc_stall_watch_check(void) return; /* idle boot, not a stall */ svc_stall_watch_dumps++; svc_stall_watch_dump(); + /* r563: self-heal after the dump (see svc_hold_bypass). */ + svc_force_consume = 4; } static int svc_thread(void *arg) |
