summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_display_engine.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_display_engine.c')
-rw-r--r--kernel/gsp_display_engine.c39
1 files changed, 36 insertions, 3 deletions
diff --git a/kernel/gsp_display_engine.c b/kernel/gsp_display_engine.c
index 7eeff0f..3e0c162 100644
--- a/kernel/gsp_display_engine.c
+++ b/kernel/gsp_display_engine.c
@@ -135,6 +135,8 @@ struct gsp_disp_chan {
u8 notifier_target; /* instance-table target: 1 FB, 2/3 sysmem */
u32 notifier_writes;
u32 notifier_posts;
+ bool event_pending; /* completion event send failed; retry in pump */
+ u32 event_drop_logs;
u32 update_logs;
/* Stats. */
@@ -1090,13 +1092,31 @@ static void gsp_disp_method(struct nv_vgpu_device *vgpu,
if (gsp_disp_events && ch->h_object) {
int rc = gsp_rm_post_channel_event(vgpu, ch->h_object);
- if (!rc)
+ if (!rc) {
ch->notifier_posts++;
+ ch->event_pending = false;
+ } else {
+ /*
+ * The event burst cap (or a transiently full
+ * status queue) silently dropped the
+ * wake-up. A completed UPDATE whose event is
+ * lost wedges the client's flip wait forever
+ * (r1636: X glxinfo stuck in
+ * os_acquire_rwlock_write), so retry from the
+ * pump instead of giving up.
+ */
+ ch->event_pending = true;
+ if (ch->event_drop_logs < 8) {
+ ch->event_drop_logs++;
+ pr_info("h=0x%x UPDATE completion event deferred rc=%d (hObj=0x%x)\n",
+ ch->hclass, rc, ch->h_object);
+ }
+ }
}
if (ch->update_logs < 8 || gsp_disp_dbg) {
ch->update_logs++;
- pr_info("h=0x%x push=0x%x UPDATE armed=%d handle=0x%x notifier=0x%llx/%u target=%u -> %s (posts=%u)\n",
- ch->hclass, push_off, armed,
+ pr_info("h=0x%x push=0x%x UPDATE armed=%d hObj=0x%x handle=0x%x notifier=0x%llx/%u target=%u -> %s (posts=%u)\n",
+ ch->hclass, push_off, armed, ch->h_object,
ch->notifier_handle, ch->notifier_pa, off_bytes,
target, wrote ? "FINISHED" : "none",
ch->notifier_posts);
@@ -1348,6 +1368,17 @@ void gsp_disp_engine_pump(struct nv_vgpu_device *vgpu)
div_u64(age, 1000000));
}
+ /*
+ * Retry a completion event whose send was refused (burst
+ * cap / transient queue state). Runs outside disp.lock:
+ * the post takes the RM status-queue lock.
+ */
+ if (s->event_pending && s->h_object && gsp_disp_events &&
+ !gsp_rm_post_channel_event(vgpu, s->h_object)) {
+ s->event_pending = false;
+ s->notifier_posts++;
+ }
+
/* Write the bookkeeping back if the slot still names this
* channel (registration may have replaced it during a boot
* round in another context). */
@@ -1371,6 +1402,8 @@ void gsp_disp_engine_pump(struct nv_vgpu_device *vgpu)
c->notifier_pa_valid = s->notifier_pa_valid;
c->notifier_writes = s->notifier_writes;
c->notifier_posts = s->notifier_posts;
+ c->event_pending = s->event_pending;
+ c->event_drop_logs = s->event_drop_logs;
c->update_logs = s->update_logs;
c->logged_update = s->logged_update;
c->last_dbg = s->last_dbg;