summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_rm_emulation.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_rm_emulation.c')
-rw-r--r--kernel/gsp_rm_emulation.c86
1 files changed, 83 insertions, 3 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 4ea6839..9d9f351 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -817,6 +817,17 @@ unsigned gsp_rm_ev_cl;
* dispatch.
*/
unsigned gsp_rm_ev_func;
+/*
+ * r1767: gate the r1765 flip-event association (hSrcResource == 0 ->
+ * alloc-header hParent). Default 0 keeps the pre-r1766 event semantics;
+ * the RCA exonerated the association from the r1766 soft-locks but not
+ * from the r1766 ISR crash class, so it stays off until validated
+ * end-to-end.
+ */
+static bool gsp_rm_ev_assoc; /* default 0: pre-r1766 event semantics */
+module_param_named(ev_assoc, gsp_rm_ev_assoc, bool, 0644);
+MODULE_PARM_DESC(ev_assoc,
+ "associate hSrcResource==0 events with their alloc parent (r1765 flip-event fix; default 0)");
static void gsp_rm_fill_ev_payload(const struct gsp_rm_emu *rm, u32 i,
u8 *payload)
@@ -870,7 +881,7 @@ static u32 gsp_rm_ev_function(void)
* serialized by rm->stat_lock and the guest is woken with MSI-X vector 0.
*/
static int gsp_rm_post_channel_event_common(struct nv_vgpu_device *vgpu,
- u32 h_src, bool force)
+ u32 h_src, bool force, bool strict)
{
struct gsp_emu_context *ctx = vgpu ? vgpu->gsp_comm_ctx : NULL;
struct gsp_rm_emu *rm;
@@ -908,6 +919,18 @@ static int gsp_rm_post_channel_event_common(struct nv_vgpu_device *vgpu,
}
/*
+ * r1765: strict mode is the display engine's 1:1 contract - a
+ * channel-scoped completion posts ONLY the events registered on the
+ * channel (a real RM fires the channel's own event list on AWAKEN).
+ * Never fall through to the all-events shotgun for such a post: the
+ * shotgun coalesces flip completions and lets unrelated completions
+ * nudge the flip event (stray FLIP_OCCURRED -> the nvidia-drm
+ * dequeue WARN). The caller's retry pump re-posts a refused edge.
+ */
+ if (!posted && strict)
+ return -ENOENT;
+
+ /*
* Fallback when the event's source object could not be associated with
* the channel: nudge every registered event. The client's dispatcher
* re-reads each channel's state on any event, so a spurious wake-up is
@@ -918,6 +941,17 @@ static int gsp_rm_post_channel_event_common(struct nv_vgpu_device *vgpu,
if (!rm->events[i].valid)
continue;
/*
+ * r1765: display-channel events are driven 1:1 by
+ * the display engine and must not be nudged by
+ * unrelated completions. The predicate answers
+ * false in the legacy default mode (gated on
+ * disp_events_strict), so this is inert unless the
+ * strict path is enabled.
+ */
+ if (gsp_disp_engine_owns_object(vgpu,
+ rm->events[i].h_src))
+ continue;
+ /*
* r580: apply the hint dedup to the per-completion
* shotgun. Every completion posts ALL registered
* events (the ABI gives no source association), so a
@@ -963,7 +997,17 @@ static int gsp_rm_post_channel_event_common(struct nv_vgpu_device *vgpu,
int gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src)
{
- return gsp_rm_post_channel_event_common(vgpu, h_src, false);
+ return gsp_rm_post_channel_event_common(vgpu, h_src, false, false);
+}
+
+/*
+ * r1765 strict variants (display engine, disp_events_strict=1): exact-match
+ * only - no all-events fallback; -ENOENT rather than a shotgun when the
+ * channel has no registered event (yet).
+ */
+int gsp_rm_post_channel_event_strict(struct nv_vgpu_device *vgpu, u32 h_src)
+{
+ return gsp_rm_post_channel_event_common(vgpu, h_src, false, true);
}
/*
@@ -980,7 +1024,13 @@ int gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src)
*/
int gsp_rm_post_channel_event_force(struct nv_vgpu_device *vgpu, u32 h_src)
{
- return gsp_rm_post_channel_event_common(vgpu, h_src, true);
+ return gsp_rm_post_channel_event_common(vgpu, h_src, true, false);
+}
+
+int gsp_rm_post_channel_event_force_strict(struct nv_vgpu_device *vgpu,
+ u32 h_src)
+{
+ return gsp_rm_post_channel_event_common(vgpu, h_src, true, true);
}
/*
@@ -1114,6 +1164,15 @@ int gsp_rm_post_all_events(struct nv_vgpu_device *vgpu)
for (i = 0; i < rm->events_n; i++) {
if (!rm->events[i].valid)
continue;
+ /*
+ * r1765: the hint must not nudge display-channel events -
+ * they are driven 1:1 by the display engine's UPDATE
+ * completions. False in the legacy default mode (the
+ * predicate is gated on disp_events_strict), so the hint is
+ * unchanged unless the strict path is enabled.
+ */
+ if (gsp_disp_engine_owns_object(vgpu, rm->events[i].h_src))
+ continue;
if (time_before(jiffies, rm->events[i].last_post +
GSPRM_EVENT_HINT_DEDUP)) {
skipped++;
@@ -3762,6 +3821,27 @@ static void gsp_rm_handle_rm_alloc(struct gsp_emu_context *ctx,
memcpy(&notify_index, params + 12, 4);
memcpy(&data64, params + 16, 8);
}
+ /*
+ * r1765: the modern NVKMS/kernel events are registered
+ * with hSrcResource = 0 in NV0005_ALLOC_PARAMETERS;
+ * their real source is the ALLOC parent object (the
+ * event is allocated ON the channel handle:
+ * hParent=0x1001b for hEvent=0x1007a, verified live).
+ * With h_src = 0 the exact-match post path never fired
+ * for display completions and every flip rode the
+ * all-events fallback, which coalesced/delayed flips
+ * and let ANY other completion nudge the flip event
+ * (stray FLIP_OCCURRED -> the nvidia-drm dequeue
+ * WARN). Fall back to the alloc header's hParent when
+ * the params name no source resource.
+ *
+ * r1767: gated behind ev_assoc (default off) until the
+ * flip fix is validated end-to-end - the r1767 RCA
+ * exonerated the association from the r1766 soft-lock
+ * class, but not from the r1766 ISR crash class.
+ */
+ if (gsp_rm_ev_assoc && h_src == 0 && hp != 0 && hp != hc)
+ h_src = hp;
rm->events[slot].h_src = h_src;
rm->events[slot].h_event = ho;
rm->events[slot].h_client = hc;