From 408d67d356ba85363a2574d420ba17cae5701d2d Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 9 Nov 2026 18:58:42 -0500 Subject: vgsp: complete the X DDX's push-buffer notifications and class-aware display arm Four fixes, built and validated on fresh boots (r1675/r1677): - gsp_display_engine: gsp_disp_update_armed() is class-aware. NVC57D (core) carries the NOTIFY bit (12:12); NVC57E (window) has no NOTIFY bit, so a bound notifier ctxDMA is the arm. Every c57e window flip computed armed=0 before this, so FINISHED and the channel event were never authored and the DDX's composite/flip waits sat out their timeout. - gsp_sema_service: complete the bfef family's NvNotification status (0x8000 -> 0) in svc_client_slot_sweep(). The DDX marks the record IN_PROGRESS before a submit and the GPU (or RM) must write it back to 0; the emulation never did. - gsp_sema_service: sema_gl_hold_apply (default 0) applies a decoded GL release forward-only at svc_gl_flush() out: when the draw section is not captured, with a stale-value and 1 MB jump guard. - gsp_sema_service: extend the 0x8000 sweep to the X DDX's own RM channels (h=0x01xxxxxx). pb_armNotifiers() writes 0x8000 at notif+0xe and pb_wait() polls it back to 0; the bfef-only filter skipped these channels, so the 8 s submit wait expired ("WAIT (2, 8, 0x8000, ...)" then "Wait for channel idle timed out") even though the class2d NOTIFY ack had zeroed the same page before the arm. Evidence: r1675 keeps the X alive past the old 212 s crash point with 0 "Caught signal" lines; the DDX's 2D pipeline runs (get word advances), the host decodes live 3D method streams (VP-METHOD ... 0x1618 BEGIN topology) and the release sweep applies thousands. --- kernel/gsp_display_engine.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'kernel/gsp_display_engine.c') 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++; -- cgit v1.2.3