summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 4a86235..aa56c5e 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -194,6 +194,28 @@ struct svc_channel {
* reset (PUT dropping below put_prev) resyncs
* last_get to slot 0 so the live first push is
* processed instead of skipped. */
+ bool gr_pub_armed; /* mm2 (r207/r208 second-client hang): a GR
+ * channel's completion word may only receive a
+ * GP_PUT publish after the channel has been
+ * proven to belong to the CURRENT session. A
+ * GR ring/USERD surviving in its fixed VRAM
+ * slot from the previous session reads a
+ * residual put at discovery (e.g. 109/112);
+ * publishing that residual put into the
+ * channel's own word (8c634144 made the target
+ * release_pa - the client's waited word) while
+ * the stale ring is consumed poisons the fresh
+ * client's UVM tracking semaphore: its
+ * completed_value observes a far-forward
+ * payload, the later reset/release sequence is
+ * a >MAX_JUMP (2*entries) downward observation,
+ * and the fresh session's first waits wedge
+ * (matmul: one GR push per channel then 242 s
+ * silent). Armed when a GR channel is seen with
+ * put <= 1 (pristine ring) or when the fresh-
+ * put-drop rewind proves a session switch; the
+ * rewind also voids any publish state the
+ * stale pass advanced. */
bool logged; /* one state log per channel */
bool pool_rel_seen; /* ISSUE-0002 r70: a pool release word for
* this channel has been read through a
@@ -11528,6 +11550,27 @@ static void svc_counter_publish(struct nv_vgpu_device *vgpu,
}
svc_counter_flush_pending(vgpu, ch);
+ /*
+ * mm2 (r207/r208 second-client hang): suppress the GR publish until
+ * the channel is proven to belong to the current session. During a
+ * fresh session's first pass the pump consumes the PREVIOUS
+ * session's residual ring; the completion gate above passes exactly
+ * then (the stale consumption satisfies last_get == put) and the
+ * residual put would land in the client's own completion word
+ * (release_pa). The fresh client's UVM then sees a far-forward
+ * payload followed by its real release sequence - a downward
+ * observation larger than UVM_GPU_SEMAPHORE_MAX_JUMP that corrupts
+ * the tracking counter and wedges the session's first waits (r207
+ * victory_matmul: 1 GR push per channel, zero forwards, 242 s).
+ * gr_pub_armed is set at the fresh-put-drop rewind (session switch
+ * proven) or when a GR channel is seen with put <= 1 (pristine
+ * ring, nothing stale to mispublish); a live mid-stream discovery
+ * (put high, never dropping) loses only this catch-up publish,
+ * which the release applies already cover.
+ */
+ if (!ch->engine_type && !ch->gr_pub_armed)
+ return;
+
val = put;
if (val == ch->counter_last)
return;
@@ -15290,6 +15333,20 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
ch->logged = true;
}
+ /*
+ * mm2: a GR channel whose USERD already reads PUT <= 1 cannot
+ * hold a stale consumed prefix, so its publishes (the catch-up
+ * for releases missing from consumed entries) are safe to
+ * enable immediately - this is the pristine first-boot ring.
+ * Channels discovered with a residual put stay unarmed until
+ * the fresh-put-drop rewind proves the session switch, so the
+ * residual put can never reach the fresh client's completion
+ * word (see gr_pub_armed and svc_counter_publish).
+ */
+ if (!ch->engine_type && !ch->gr_pub_armed && put <= 1 &&
+ !ch->userd_wait_fresh)
+ ch->gr_pub_armed = true;
+
/* Initialize expected semaphore payload from the pool (if mapped). */
svc_init_expected_payload(vgpu, ch);
@@ -15384,6 +15441,36 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
ch->h_object, ch->gr_index, put,
(u32)ch->last_get);
ch->last_get = 0;
+ /*
+ * mm2: the session switch is now proven - arm
+ * the publish for the live entries that follow,
+ * and void any publish state the stale pass
+ * advanced. Everything consumed to reach
+ * last_get was the dead session's ring; a
+ * publish issued on it wrote the residual put
+ * into the very word the fresh client waits on
+ * (its tracking semaphore; pub target is
+ * release_pa since 8c634144) and the
+ * forward-only apply then skips the real
+ * release payloads that follow. Re-arm the
+ * word to 0 and reset the catch-up bookkeeping
+ * so the re-decoded live releases re-advance
+ * it from the client's own sequence (1, 2,
+ * ...). Idempotent when no stale publish
+ * happened (counter_last == 0).
+ */
+ ch->gr_pub_armed = true;
+ if (ch->counter_last) {
+ u64 upa = ch->release_pa ?
+ ch->release_pa : ch->counter_pa;
+ u32 zero = 0;
+
+ if (upa)
+ (void)svc_write_ap(vgpu, upa,
+ SVC_APERTURE_SYS,
+ &zero, sizeof(zero));
+ ch->counter_last = 0;
+ }
}
bitmap_zero(ch->slot_done_epoch, SVC_GPFIFO_MAX_BITS);
}