summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c257
1 files changed, 145 insertions, 112 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index d9a0fd6..77a1fae 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -1041,6 +1041,8 @@ struct svc_fwd_rel;
static bool svc_opdef_release(struct nv_vgpu_device *vgpu,
struct svc_channel *ch, u32 entry_idx,
bool rescue, const struct svc_fwd_rel *r);
+static void svc_opdef_drop(struct nv_vgpu_device *vgpu,
+ struct svc_channel *ch, u32 entry_idx);
static void svc_opdef_reset_all(void);
void gsp_sema_service_channel_del(u32 h_object)
@@ -5981,12 +5983,19 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
* only the apply moves. Overflow applies inline.
*/
/*
- * ISSUE-0002 (r62): an unresolved operand of
- * this pass owns the entry and its releases;
- * svc_opdef_release records this one for the
- * hold (or applies a completed set) so the
- * client cannot pass the release before the
- * retried op runs.
+ * ISSUE-0002 (r62/r65): an unresolved operand
+ * of this pass holds the entry. Order matters:
+ * a captured forwarding candidate owns the
+ * release (the forwarded hardware copy's
+ * completion is the delivery edge - r65: a
+ * software apply here let the client pass the
+ * launch-completion wait while the physical
+ * launch was still in flight and later timed
+ * out, so the client read zeros); only when no
+ * candidate is captured does the operand hold
+ * own the release, and then it is recorded
+ * instead of applied so the client cannot pass
+ * it before the retried op runs.
*/
{
struct svc_fwd_rel or;
@@ -5997,14 +6006,9 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
or.va = va;
or.payload = payload;
or.entry_idx = entry_idx;
- if (svc_opdef_release(vgpu, ch, entry_idx,
- replay, &or)) {
- /*
- * Held with the entry (or an
- * earlier set was applied
- * here): no inline apply.
- */
- } else if (svc_fwd_defer_arm()) {
+ if (svc_fwd_defer_arm()) {
+ svc_opdef_drop(vgpu, ch,
+ entry_idx);
if (svc_fwd_rel_n < SVC_FWD_REL_MAX) {
struct svc_fwd_rel *r =
&svc_fwd_rel[svc_fwd_rel_n++];
@@ -6034,6 +6038,14 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
va, payload,
op);
}
+ } else if (svc_opdef_release(vgpu, ch,
+ entry_idx,
+ replay, &or)) {
+ /*
+ * Held with the entry (or an
+ * earlier set was applied
+ * here): no inline apply.
+ */
} else {
svc_rel_apply_906f(vgpu, ch,
va, payload, op);
@@ -6114,36 +6126,17 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
}
n_ops = 0;
/*
- * ISSUE-0002 (r62): an unresolved operand
- * of this pass owns the entry and its
- * releases; svc_opdef_release records
- * this one for the hold (or applies a
- * completed set) so the client cannot
- * pass the release before the retried
- * op runs.
- */
- {
- struct svc_fwd_rel or;
-
- memset(&or, 0, sizeof(or));
- or.kind = SVC_FWD_REL_REPORTSEM;
- or.va = va;
- or.payload = st.rs_payload;
- or.entry_idx = entry_idx;
- if (svc_opdef_release(vgpu, ch,
- entry_idx,
- replay, &or))
- break;
- }
- /*
- * P6b wave 1.5: with a forwarding
- * candidate captured and the deferral
- * knob on, record the release instead
- * of applying it; the pump applies it
- * once the forwarded copy completes.
- * Overflow applies inline.
+ * ISSUE-0002 (r62/r65): a captured
+ * forwarding candidate owns the
+ * release (the hardware completion
+ * is the delivery edge); only
+ * without one does the operand hold
+ * own it, and then it is recorded
+ * instead of applied.
*/
if (svc_fwd_defer_arm()) {
+ svc_opdef_drop(vgpu, ch,
+ entry_idx);
if (svc_fwd_rel_n < SVC_FWD_REL_MAX) {
struct svc_fwd_rel *r =
&svc_fwd_rel[svc_fwd_rel_n++];
@@ -6170,6 +6163,18 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
*/
svc.fwd_rel_overflow++;
svc_fwd_soft_copy_inline(vgpu);
+ } else {
+ struct svc_fwd_rel or;
+
+ memset(&or, 0, sizeof(or));
+ or.kind = SVC_FWD_REL_REPORTSEM;
+ or.va = va;
+ or.payload = st.rs_payload;
+ or.entry_idx = entry_idx;
+ if (svc_opdef_release(vgpu, ch,
+ entry_idx,
+ replay, &or))
+ break;
}
svc_rel_apply_reportsem(vgpu, ch, va,
st.rs_payload);
@@ -6597,13 +6602,18 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
* release as decoded. Overflow applies inline.
*/
/*
- * ISSUE-0002 (r62): an unresolved operand of
- * this pass owns the entry and its releases;
- * svc_opdef_release records this one (with its
+ * ISSUE-0002 (r62/r65): a captured forwarding
+ * candidate owns the release - the forwarded
+ * hardware copy's completion is the delivery
+ * edge. r65: applying it here (operand-hold
+ * path) let the client pass the launch-
+ * completion wait while the physical launch
+ * was still in flight and later timed out, so
+ * the client read zeros. Only without a
+ * candidate does the operand hold own the
+ * release, and then it is recorded (with its
* one-shot increment claim and raw launch word)
- * for the hold, or applies the completed set,
- * so the client cannot pass the release before
- * the retried op runs.
+ * instead of applied.
*/
{
struct svc_fwd_rel or;
@@ -6616,81 +6626,89 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
or.payload = st.sem_payload;
or.entry_idx = entry_idx;
or.dma = dma;
- if (svc_opdef_release(vgpu, ch,
- entry_idx, replay,
- &or)) {
+ if (svc_fwd_defer_arm()) {
+ svc_opdef_drop(vgpu, ch,
+ entry_idx);
+ if (svc_fwd_rel_n < SVC_FWD_REL_MAX) {
+ struct svc_fwd_rel *r =
+ &svc_fwd_rel[svc_fwd_rel_n++];
+
+ r->kind = SVC_FWD_REL_LAUNCH;
+ r->op = pending ? 1 : 0;
+ r->inc_claimed = inc_apply ? 1 : 0;
+ r->va = sem_va;
+ r->payload = st.sem_payload;
+ r->entry_idx = entry_idx;
+ r->dma = dma;
+ svc_fwd_relay_note(vgpu, ch, r,
+ dma, true);
+ /*
+ * P6b wave 1.5: do
+ * NOT bump
+ * svc.pushes_pending
+ * here -
+ * svc_rel_apply_launch()
+ * counts it once when
+ * the deferred record
+ * is applied (or drops
+ * it unapplied).
+ */
+ svc_rel_va_seen = sem_va;
+ svc_rel_count++;
+ svc_fwd_defer_armed = true;
+ svc.fwd_rel_deferred++;
+ } else {
+ /*
+ * P6b wave 2: an
+ * overflowed release
+ * still applies inline;
+ * author a withheld
+ * candidate first.
+ */
+ svc.fwd_rel_overflow++;
+ svc_fwd_soft_copy_inline(vgpu);
+ if (svc_rel_apply_launch(vgpu, ch,
+ sem_va,
+ st.sem_payload,
+ cur, pending,
+ inc, inc_apply)) {
+ svc_rel_va_seen = sem_va;
+ svc_rel_count++;
+ }
+ }
+ } else if (svc_opdef_release(vgpu, ch,
+ entry_idx,
+ replay, &or)) {
/* release ends the push */
n_ops = 0;
break;
- }
- }
- if (svc_fwd_defer_arm()) {
- if (svc_fwd_rel_n < SVC_FWD_REL_MAX) {
- struct svc_fwd_rel *r =
- &svc_fwd_rel[svc_fwd_rel_n++];
-
- r->kind = SVC_FWD_REL_LAUNCH;
- r->op = pending ? 1 : 0;
- r->inc_claimed = inc_apply ? 1 : 0;
- r->va = sem_va;
- r->payload = st.sem_payload;
- r->entry_idx = entry_idx;
- r->dma = dma;
- svc_fwd_relay_note(vgpu, ch, r,
- dma, true);
- /*
- * P6b wave 1.5: do NOT bump
- * svc.pushes_pending here -
- * svc_rel_apply_launch()
- * counts it once when the
- * deferred record is applied
- * (or drops it unapplied).
- */
- svc_rel_va_seen = sem_va;
- svc_rel_count++;
- svc_fwd_defer_armed = true;
- svc.fwd_rel_deferred++;
} else {
/*
- * P6b wave 2: an overflowed
- * release still applies
- * inline; author a withheld
- * candidate first.
+ * Deferral is enabled but no
+ * forwarded hardware copy can
+ * run for this push
+ * (guest-memory copy path
+ * off, or no candidate):
+ * apply the decoded release
+ * directly, exactly once.
+ * The note is the proof line
+ * that a decoded release is
+ * never left to a copy that
+ * will not engage.
*/
- svc.fwd_rel_overflow++;
- svc_fwd_soft_copy_inline(vgpu);
- if (svc_rel_apply_launch(vgpu, ch,
- sem_va,
+ if (gsp_phys_work_defer_release_enabled() &&
+ svc_fwd_cand.valid)
+ svc_fwd_rel_direct_note(ch->h_object,
+ sem_va,
+ st.sem_payload);
+ if (svc_rel_apply_launch(vgpu, ch, sem_va,
st.sem_payload,
- cur, pending,
- inc, inc_apply)) {
+ cur, pending, inc,
+ inc_apply)) {
svc_rel_va_seen = sem_va;
svc_rel_count++;
}
}
- } else {
- /*
- * Deferral is enabled but no forwarded
- * hardware copy can run for this push
- * (guest-memory copy path off, or no
- * candidate): apply the decoded release
- * directly, exactly once. The note is
- * the proof line that a decoded release
- * is never left to a copy that will
- * not engage.
- */
- if (gsp_phys_work_defer_release_enabled() &&
- svc_fwd_cand.valid)
- svc_fwd_rel_direct_note(ch->h_object,
- sem_va,
- st.sem_payload);
- if (svc_rel_apply_launch(vgpu, ch, sem_va,
- st.sem_payload,
- cur, pending, inc,
- inc_apply)) {
- svc_rel_va_seen = sem_va;
- svc_rel_count++;
- }
}
/* release ends the push */
n_ops = 0;
@@ -10894,6 +10912,21 @@ static void svc_opdef_flush(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
}
/*
+ * The forwarding machinery owns this release now (a candidate was captured
+ * for the pass and its record set carries the same release): drop any
+ * record a held-operand pass left for this entry without applying it, so
+ * the forwarded hardware copy's completion is the single delivery edge.
+ */
+static void svc_opdef_drop(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
+ u32 entry_idx)
+{
+ struct svc_opdef_ent *e = svc_opdef_find(vgpu, ch->h_object, entry_idx);
+
+ if (e)
+ svc_opdef_clear(e);
+}
+
+/*
* The ring advanced past a slot's entry (a slot for another entry of the
* same channel is being processed): its set belongs to a consumed entry.
* Deliver late (forward-only, so it cannot double-apply) and drop it.