summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c36
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)