diff options
| -rw-r--r-- | kernel/gsp_display_engine.c | 39 |
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; |
