summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_sema_service.c64
1 files changed, 57 insertions, 7 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 57a6ba5..e57bcac 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -13295,6 +13295,21 @@ static void svc_opdef_drop_stale(struct nv_vgpu_device *vgpu,
if (!e->active || e->vgpu != vgpu ||
e->h_object != ch->h_object || e->entry_idx == keep_idx)
continue;
+ /*
+ * STALLFREE r228 (entry=82 of 0x5c000059): a slot whose entry
+ * the ring has NOT consumed in this put epoch is NOT stale. A
+ * pin-batch rewind moves last_get backwards over an unconsumed
+ * entry and re-decodes it; clearing the slot here restarted the
+ * 10 s opdef deadline on every re-walk, so the hold re-armed
+ * forever (log: 'opdef-clear caller=4 entry=82' + 'opdef: hold
+ * entry=82' repeating while the 1 MiB op's operand never
+ * resolved, rc=-2; put=84 get=82 last=82 frozen for 10 s). The
+ * epoch bit is set by svc_replay_note on consume, so only an
+ * entry that was truly consumed has its withheld set
+ * delivered-late and dropped here.
+ */
+ if (!test_bit(e->entry_idx, ch->slot_done_epoch))
+ continue;
if (e->n)
svc_fwd_rel_apply_all(vgpu, ch, e->rel, e->n);
svc_opdef_clear(e, SVC_OPDEF_CLR_STALE);
@@ -16460,8 +16475,8 @@ static void svc_userd_sweep(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu,
struct svc_channel *ch, u32 put, u32 get)
{
- bool catchup, residual, dead_reset, replay_cand;
- bool fire_replay, fire_reset;
+ bool catchup, residual, dead_reset, replay_cand, stalled_cand;
+ bool fire_replay, fire_reset, fire_stall;
const char *reason = "";
unsigned long waited;
@@ -16507,7 +16522,27 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu,
dead_reset = (catchup && put > 1 && !ch->wd_epoch_done &&
!ch->gr_pub_armed && ch->counter_last == 0 &&
ch->submissions >= 8);
- if (!residual && !dead_reset && !replay_cand) {
+ /*
+ * STALLFREE r228: stalled PENDING entry. The producer has submitted
+ * work the host has not consumed (put > get) and the entry loop has
+ * made no progress - position AND submissions static across the
+ * window - while no bounded owner is active for the stuck entry: no
+ * unreadable-push grace (defer_since), no no-capture window, no
+ * opdef operand slot, no m150 hold window. That combination is a
+ * genuinely unexplained stall (r228: the opdef deadline kept being
+ * reset by rewind replays, fixed in svc_opdef_drop_stale; this leg
+ * is the safety net for any future variant that slips the bounded
+ * owners). A green channel always advances submissions (consume) or
+ * sets one of the bounded owners on a pending entry, so the leg
+ * cannot fire there.
+ */
+ stalled_cand = (!catchup && put != get && !ch->defer_since &&
+ !ch->gr_nocap_since &&
+ !(ch->gr_hold_idx == (u32)ch->last_get &&
+ time_before(jiffies, ch->gr_hold_until)) &&
+ !svc_opdef_find(vgpu, ch->h_object,
+ (u32)ch->last_get));
+ if (!residual && !dead_reset && !replay_cand && !stalled_cand) {
ch->wd_since = 0;
ch->wd_put = put;
ch->wd_last_get = ch->last_get;
@@ -16533,7 +16568,13 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu,
* which the existing grace paths own.
*/
fire_replay = replay_cand && ch->submissions != ch->wd_sub;
- if (!residual && !fire_reset && !fire_replay) {
+ /*
+ * The stalled-entry leg fires only with proof of no progress at all:
+ * nothing was consumed during the window (submissions static), so
+ * the entry is genuinely parked with no bounded owner.
+ */
+ fire_stall = stalled_cand && ch->submissions == ch->wd_sub;
+ if (!residual && !fire_reset && !fire_replay && !fire_stall) {
ch->wd_since = 0;
return;
}
@@ -16560,7 +16601,13 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu,
ch->counter_last = 0;
}
}
- if (fire_reset) {
+ if (fire_reset || fire_stall) {
+ /*
+ * The canonical unstuck: rewind to slot 0 so the fresh
+ * session's own entries (which start there) get walked, with
+ * forced replay (wd_nocap_put) so the re-walk decodes releases
+ * only and never re-captures a launch; once per put epoch.
+ */
ch->wd_epoch_done = true;
ch->last_get = 0;
ch->wd_nocap_put = put;
@@ -16581,12 +16628,15 @@ static void svc_gr_stale_wedge_check(struct nv_vgpu_device *vgpu,
reason = "stale-replay";
else if (fire_reset)
reason = "stale-dead-range";
+ else if (fire_stall)
+ reason = "stale-entry";
else
reason = "stale-epoch";
- pr_warn_ratelimited("vgsp-gr: GR-STALL-stale-wedge h=0x%x va=0x%llx last=%u put=%u get=%u sub=%llu waited_ms=%u action=recover reason=%s reset=%d rewind=%d cpa=0x%llx rpa=0x%llx\n",
+ pr_warn_ratelimited("vgsp-gr: GR-STALL-stale-wedge h=0x%x va=0x%llx last=%u put=%u get=%u sub=%llu waited_ms=%u action=recover reason=%s reset=%d rewind=%d entry=%d cpa=0x%llx rpa=0x%llx\n",
ch->h_object, ch->gpfifo_va, (u32)ch->last_get,
put, get, ch->submissions, waited, reason,
- fire_reset ? 1 : 0, fire_replay ? 1 : 0,
+ (fire_reset || fire_stall) ? 1 : 0,
+ fire_replay ? 1 : 0, fire_stall ? 1 : 0,
ch->counter_pa, ch->release_pa);
}