summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.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_sema_service.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_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c103
1 files changed, 102 insertions, 1 deletions
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
@@ -11314,6 +11330,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
* 24 B release pushes), not to this section; wiping it here and at
@@ -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;