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.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index c1b98f3..37b2200 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -512,11 +512,14 @@ static int gsp_rm_send_flags(struct gsp_emu_context *ctx, u32 function,
: GSPRM_EVENT_BURST_MAX;
/* m171: expire the budget by wall time so a long-ago
- * flood can never starve a fresh completion post. */
+ * flood can never starve a fresh completion post. Only an
+ * admitted record moves the window: a refused attempt that
+ * retried (the display completion retry runs every 250 ms)
+ * must not keep the window perpetually fresh, or the budget
+ * would never expire and the retry would livelock. */
if (time_after(jiffies, rm->event_burst_at +
GSPRM_EVENT_BURST_WINDOW))
rm->event_burst = 0;
- rm->event_burst_at = jiffies;
if (rm->event_burst >= cap) {
rm->events_dropped++;
if (rm->events_dropped <= 8 ||
@@ -529,6 +532,7 @@ static int gsp_rm_send_flags(struct gsp_emu_context *ctx, u32 function,
kfree(buf);
return -EAGAIN;
}
+ rm->event_burst_at = jiffies;
rm->event_burst++;
} else {
rm->event_burst = 0;
@@ -850,7 +854,8 @@ static u32 gsp_rm_ev_function(void)
* Safe to call from the progress service's thread: the status queue write is
* serialized by rm->stat_lock and the guest is woken with MSI-X vector 0.
*/
-int gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src)
+static int gsp_rm_post_channel_event_common(struct nv_vgpu_device *vgpu,
+ u32 h_src, bool force)
{
struct gsp_emu_context *ctx = vgpu ? vgpu->gsp_comm_ctx : NULL;
struct gsp_rm_emu *rm;
@@ -908,7 +913,8 @@ int gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src)
* client's dispatcher re-reads channel state on any
* event - and the 0.5 s hint re-posts late waiters.
*/
- if (time_before(jiffies, rm->events[i].last_post +
+ if (!force &&
+ time_before(jiffies, rm->events[i].last_post +
GSPRM_EVENT_HINT_DEDUP))
continue;
gsp_rm_fill_ev_payload(rm, i, payload);
@@ -940,6 +946,28 @@ int gsp_rm_post_channel_event(struct nv_vgpu_device *vgpu, u32 h_src)
return posted ? 0 : -ENOENT;
}
+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);
+}
+
+/*
+ * Force a completion wake-up past the hint dedup. The 250 ms dedup assumes a
+ * recent post already woke the client, but a waiter that arrived after that
+ * post misses it, and a busy event stream keeps refreshing every event's
+ * stamp so the coalesced completion is never delivered (r1649: the X server's
+ * display UPDATE completion was refused - the coincident hint returned
+ * -EAGAIN because every event was inside the window - and the flip wait spun
+ * in the nvidia ioctl forever). Callers use this only for a refused
+ * completion edge, rate-limited by their own retry window; the event burst
+ * cap and the status-ring free-space discipline still apply inside
+ * gsp_rm_send_flags().
+ */
+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);
+}
+
/*
* r623 experiment: deliver a synthetic OS_ERROR_LOG (0x1006) record to the
* guest's RM queue - the error report a real GSP sends into the client's