summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-08 18:03:27 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-08 18:03:27 -0500
commit6cd260b87557e881af1e47f82ff3f0df79d30e44 (patch)
treef5b0a8195e0302268376bea562f697b23ad93727 /kernel
parentd15e391b6a38a61e0996ef2091dd1ef7bda279e3 (diff)
downloadopen-iov-6cd260b87557e881af1e47f82ff3f0df79d30e44.tar.gz
open-iov-6cd260b87557e881af1e47f82ff3f0df79d30e44.zip
vgsp-disp: retry a lost UPDATE completion event from the pump
r1636: the X-start mode set wrote FINISHED but the channel completion event was refused (event burst cap / transient status-queue state) and never retried, so NVKMS waited forever and X wedged in os_acquire_rwlock_write. Mark the channel event_pending on a failed post, retry it every pump pass (outside disp.lock), clear on success, and log the failure/recovery plus hObj in the UPDATE line.
Diffstat (limited to 'kernel')
-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;