summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_display_engine.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-09 18:58:42 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-09 18:58:42 -0500
commit408d67d356ba85363a2574d420ba17cae5701d2d (patch)
tree18199807549d2060bc76be4f2076926e8c4bf542 /kernel/gsp_display_engine.c
parentc38872182f2eb11660887ba73188d22a6b3835de (diff)
downloadopen-iov-408d67d356ba85363a2574d420ba17cae5701d2d.tar.gz
open-iov-408d67d356ba85363a2574d420ba17cae5701d2d.zip
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.
Diffstat (limited to 'kernel/gsp_display_engine.c')
-rw-r--r--kernel/gsp_display_engine.c37
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++;