summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
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;