diff options
Diffstat (limited to 'kernel/gsp_display_engine.c')
| -rw-r--r-- | kernel/gsp_display_engine.c | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/kernel/gsp_display_engine.c b/kernel/gsp_display_engine.c index a6dd11c..c97458c 100644 --- a/kernel/gsp_display_engine.c +++ b/kernel/gsp_display_engine.c @@ -144,6 +144,7 @@ struct gsp_disp_chan { unsigned long event_retry_at; /* next forced re-post attempt */ u32 event_drop_logs; u32 update_logs; + u32 ctrl_logs; /* Stats. */ u64 updates; @@ -1014,6 +1015,29 @@ void gsp_disp_engine_channel_add(struct nv_vgpu_device *vgpu, u32 hclass, * else is state the engine would apply to the display pipeline (head/window/ * cursor registers) which we deliberately do not render. */ +/* + * Is this UPDATE's notifier armed? + * + * NVC57D (core) SET_NOTIFIER_CONTROL carries a NOTIFY bit (12:12) and the + * class disables the notifier with ctxDMA 0 + control 0. + * + * NVC57E (window) SET_NOTIFIER_CONTROL has only MODE (0:0) and OFFSET + * (11:4); there is no NOTIFY bit. The bound notifier ctxDMA *is* the + * enable, and the class disables with ctxDMA 0 + control 0. Treating + * bit 12 as the arm bit made every window flip compute armed=0, so the + * emulation never wrote FINISHED and never posted the channel event for + * the X server's window channel (0xc57e). The DDX's composite/flip + * waits then sat out their timeout (Xorg log "Wait for channel idle + * timed out") and the display pipeline stalled. + */ +static bool gsp_disp_update_armed(const struct gsp_disp_chan *ch) +{ + if (ch->hclass == GSP_DISP_CLASS_CORE) + return (ch->notifier_ctrl & + GSP_DISP_NOTIFIER_CTRL_NOTIFY) != 0; + return ch->notifier_handle != 0 && ch->notifier_pa_valid; +} + static void gsp_disp_method(struct nv_vgpu_device *vgpu, struct gsp_disp_chan *ch, u32 addr, u32 value, u32 push_off) @@ -1048,11 +1072,15 @@ static void gsp_disp_method(struct nv_vgpu_device *vgpu, } if (addr == notifier_ctrl) { ch->notifier_ctrl = value; - if (gsp_disp_dbg) - pr_info("h=0x%x push=0x%x SET_NOTIFIER_CTRL=0x%x (notify=%u off=%u)\n", + if (gsp_disp_dbg || ch->ctrl_logs < 8) { + ch->ctrl_logs++; + pr_info("h=0x%x push=0x%x SET_NOTIFIER_CTRL=0x%x (notify=%u off=%u armed=%d handle=0x%x pa_valid=%d)\n", ch->hclass, push_off, value, !!(value & GSP_DISP_NOTIFIER_CTRL_NOTIFY), - GSP_DISP_NOTIFIER_CTRL_OFFSET(value)); + GSP_DISP_NOTIFIER_CTRL_OFFSET(value), + gsp_disp_update_armed(ch), + ch->notifier_handle, ch->notifier_pa_valid); + } return; } if (addr == GSP_DISP_M_UPDATE) { @@ -1060,8 +1088,7 @@ static void gsp_disp_method(struct nv_vgpu_device *vgpu, u64 pa = ch->notifier_pa + off_bytes; u32 target = ch->notifier_target; u32 finished = GSP_DISP_NOTIFIER_FINISHED; - bool armed = (ch->notifier_ctrl & - GSP_DISP_NOTIFIER_CTRL_NOTIFY) != 0; + bool armed = gsp_disp_update_armed(ch); bool wrote = false; ch->updates++; |
