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_sema_service.c | 103 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) (limited to 'kernel/gsp_sema_service.c') diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index c805fb5..5c638a5 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -9106,6 +9106,22 @@ static bool gsp_sema_gl_draw_synth; module_param_named(sema_gl_draw_synth, gsp_sema_gl_draw_synth, bool, 0644); MODULE_PARM_DESC(sema_gl_draw_synth, "Capture a draw-shaped C597 section with the dev fallback operands when the client supplied none (default 0 since r929; witness marks src=draw-synth)"); + +/* + * Apply a decoded GL release forward-only when the draw section is not + * captured. The GLX client's kickoff suffix releases the shared-surface + * refCount (sharedSurface+0x800+0x10*sd) that the X DDX's nvClipIdleChannels + * polls; if the draw section never reaches a capturable flush the release + * stayed in svc_gl/svc_gl_hold_tab and the DDX sat out its 5 s timeout + * ("Wait for channel idle timed out"). The release is the only edge the + * client needs here (no host-side draw work to order against), so applying + * it when the section is skipped is safe; forward-only + jump-bound guards + * make a duplicate/stale apply harmless. + */ +static bool gsp_sema_gl_hold_apply; +module_param_named(sema_gl_hold_apply, gsp_sema_gl_hold_apply, bool, 0644); +MODULE_PARM_DESC(sema_gl_hold_apply, + "Apply a decoded GL release forward-only when the draw section is not captured (default 0)"); #define SVC_GL_SYNTH_PROG_VA 0x121201b00ULL #define SVC_GL_SYNTH_PARAM_VA 0x1214fa220ULL #define SVC_GL_SYNTH_PARAM_SIZE 0x10u @@ -11313,6 +11329,30 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu, } } out: + /* + * Apply the decoded GL release forward-only, whether the section was + * captured or skipped. The GLX client's kickoff suffix releases the + * shared-surface refCount that the X DDX's nvClipIdleChannels polls; + * when the forwarded draw does not complete (or the section is not + * capturable) the release stayed held and the DDX sat out its 5 s + * timeout. The release is the only edge the client needs; the + * forward-only + jump-bound guards make a duplicate/stale apply + * harmless. Gated by sema_gl_hold_apply for A/B. + */ + if (gsp_sema_gl_hold_apply && svc_gl.rel_va && svc_gl.rel_payload) { + u32 cur = 0; + + if (svc_sem_read(vgpu, svc_gl.rel_va, &cur)) { + svc_pending_add(svc_gl.rel_va, svc_gl.rel_payload, 0); + } else if (svc_gl.rel_payload > cur && + svc_gl.rel_payload - cur <= 0x100000) { + if (!svc_sem_write(vgpu, 0, svc_gl.rel_va, + svc_gl.rel_payload)) + pr_info("sema-gl: hold applied va=0x%llx pay=%u (cur=%u)\n", + svc_gl.rel_va, svc_gl.rel_payload, + cur); + } + } /* * SESSION 149 R15 (M1.1a): preserve the last valid release across * the reset - it belongs to the channel (decoded from the bracketing @@ -26390,7 +26430,22 @@ static void svc_client_slot_sweep(struct nv_vgpu_device *vgpu) if (!c->valid || c->vgpu != vgpu || !c->notifier_pa) continue; - if ((c->h_object & 0xfffff000u) != 0xbeef0000u) + /* + * CONT.387: the X DDX's own RM channels (h=0x01000014 and + * siblings, allocated by our RM for the server's nvidia.ko + * clients) use the same push-buffer NvNotification contract + * as the bfef family: pb_armNotifiers() writes 0x8000 at + * notif+0xe before a submit and pb_wait() polls it back to 0. + * The bfef-only filter skipped them, so the DDX's 8 s submit + * wait expired (Xorg log "WAIT (2, 8, 0x8000, ...)" then + * "Wait for channel idle timed out") even though the class2d + * NOTIFY ack had already zeroed the same page at decode time + * (before the arm). Include the 0x01xxxxxx RM-channel family + * in the sweep so the armed record is completed after the arm. + */ + if ((c->h_object & 0xfffff000u) != 0xbeef0000u && + (c->h_object & 0xfffff000u) != 0xbfef0000u && + (c->h_object & 0xff000000u) != 0x01000000u) continue; tab[n].h = c->h_object; tab[n].base = c->notifier_pa; @@ -26403,6 +26458,52 @@ static void svc_client_slot_sweep(struct nv_vgpu_device *vgpu) u64 page = tab[i].base & ~((u64)SEMA_PAGE_SIZE - 1); int k; + /* + * The bfef family (the GLX client's kick channel) is the X + * DDX's 2D channel. Its NvNotification status halfword is + * marked 0x8000 (IN_PROGRESS) before a submit and the GPU + * (or RM) must write it back to 0; the emulation never did, + * so the DDX's 8 s submit wait expired and its recovery + * path (dc3d0) released the channel group and then + * dereferenced it (SIGSEGV at 0x28 in nvidia_drv.so). + * Complete every 0x8000 record in the notifier page. A + * 0xffff here is the delivered-error value and is left + * alone (the beef loop below owns the 0xffff semantics). + */ + if (((tab[i].h & 0xfffff000u) == 0xbfef0000u || + (tab[i].h & 0xff000000u) == 0x01000000u) && + time_after_eq(jiffies, svc_kick_complete_at)) { + static u8 npage[SEMA_PAGE_SIZE]; + static u32 bfef_done_n; + + if (!svc_read_ap(vgpu, page, tab[i].as, npage, + sizeof(npage))) { + for (k = 0; k < SEMA_PAGE_SIZE / 16; k++) { + u16 *st = (u16 *)(npage + 0x0e + + (u64)k * 16); + u16 z = 0; + + if (*st != 0x8000) + continue; + if (svc_write_ap(vgpu, + page + 0x0e + + (u64)k * 16, + tab[i].as, &z, + sizeof(z))) + continue; + bfef_done_n++; + if (gsp_sema_dbg && bfef_done_n <= 64) + pr_info("sema-chan: bfef notif completed h=0x%x slot=%d pa=0x%llx n=%u\n", + tab[i].h, k, + page + 0x0e + + (u64)k * 16, + bfef_done_n); + } + } + } + + if ((tab[i].h & 0xfffff000u) != 0xbeef0000u) + continue; for (k = 0; k < 6; k++) { u64 pa = page + 0x0e + (u64)k * SVC_NOTIFY_SIZE; u16 st = 0, z = 0; -- cgit v1.2.3