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.c75
1 files changed, 64 insertions, 11 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 6ce84f1..ebbe3bd 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -18098,6 +18098,7 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object,
u32 n3800 = 0, n39c8 = 0, n39d0 = 0, n2380 = 0;
u32 n238c = 0, n2390 = 0, n3460 = 0;
u32 b3800_first = 0xffffffffu;
+ u32 subch_seen = 0xffffffffu;
(void)vgpu;
/*
@@ -18119,7 +18120,7 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object,
if (base && base != svc_gl_cb_img_base)
svc_gl_cb_img_reset(base);
while (off + 4u <= len) {
- u32 hdr, op, cnt, addr, w;
+ u32 hdr, op, cnt, addr, subch, w;
memcpy(&hdr, buf + off, 4);
nhdr++;
@@ -18129,7 +18130,18 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object,
}
op = (hdr >> 29) & 7u;
cnt = (hdr >> 16) & 0xfffu;
- addr = (hdr & 0x1fffu) << 2;
+ /*
+ * The method header is the A16F DMA encoding: method address
+ * 11:0 (dwords), subchannel 15:13, count 28:16. The old
+ * 0x1fff mask folded the reserved bit 12 into the address, so
+ * a header whose bit 12 is set decoded 0x4000 high and the
+ * 0x3800/0x39c8/0x2390 targets were never matched (CB-DIAG
+ * n3800/n39c8/n2390 = 0 on every push).
+ */
+ addr = (hdr & 0xfffu) << 2;
+ subch = (hdr >> 13) & 0x7u;
+ if (subch_seen == 0xffffffffu)
+ subch_seen = subch;
if (op == 0u || op == 2u || op == 7u) {
off += 4u;
continue;
@@ -18156,14 +18168,22 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object,
svc_gl_cb_off = w;
dirty = true;
} else if (addr == 0x2384u) {
+ /*
+ * SELECTOR_B = ADDRESS_UPPER (bits 7:0 of the
+ * word are cb addr[39:32]); it is the HIGH half
+ * of the 64-bit address, not the low one. The
+ * historical packing put B in the low dword and
+ * C in the high dword (swapped).
+ */
svc_gl_cb_sel_bc = (svc_gl_cb_sel_bc &
- ~0xffffffffULL) |
- (u64)w;
+ 0xffffffffULL) |
+ ((u64)w << 32);
svc_gl_cb_sel_seen = true;
} else if (addr == 0x2388u) {
+ /* SELECTOR_C = ADDRESS_LOWER (addr[31:0]). */
svc_gl_cb_sel_bc = (svc_gl_cb_sel_bc &
- 0xffffffffULL) |
- ((u64)w << 32);
+ ~0xffffffffULL) |
+ (u64)w;
svc_gl_cb_sel_seen = true;
} else if (addr == 0x3800u) {
/*
@@ -18212,9 +18232,37 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object,
else if (addr >= 0x2390u && addr < 0x2390u + 0x1000u)
n2390++;
if (addr == 0x238cu) {
+ /*
+ * LOAD_CONSTANT_BUFFER_OFFSET with inline data (the
+ * driver's own emission, nv3dLoadConstantsHeader /
+ * nv3dLoadSingleConstant): the run payload is
+ * [offset][constant dwords...]. Word 0 sets the CB
+ * load offset; the rest stream through the
+ * LOAD_CONSTANT_BUFFER data port at successive
+ * offsets. Only word 0 used to be applied, so an
+ * upload carried this way landed nothing.
+ */
memcpy(&w, buf + off + 4u, 4);
svc_gl_cb_off = w;
dirty = true;
+ if (op != 3u && cnt > 1u) {
+ u32 j;
+
+ for (j = 1; j < cnt; j++) {
+ u64 doff = (u64)svc_gl_cb_off +
+ 4ULL * (u64)(j - 1u);
+
+ if (doff + 4ULL > SVC_GL_CB_IMG_LIMIT)
+ continue;
+ memcpy(&w, buf + off + 4u +
+ 4u * j, 4);
+ memcpy(svc_gl_cb_img + doff, &w, 4);
+ words++;
+ dirty = true;
+ }
+ svc_gl_cb_off += 4u * (cnt - 1u);
+ runs++;
+ }
off += 4u + cnt * 4u;
continue;
}
@@ -18230,17 +18278,21 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object,
svc_gl_cb_sel_a = w;
break;
case 0x2384u:
+ /* SELECTOR_B = ADDRESS_UPPER: high
+ * dword of the cb address (see the
+ * IMMD branch above). */
svc_gl_cb_sel_bc =
(svc_gl_cb_sel_bc &
- ~0xffffffffULL) |
- (u64)w;
+ 0xffffffffULL) |
+ ((u64)w << 32);
svc_gl_cb_sel_seen = true;
break;
case 0x2388u:
+ /* SELECTOR_C = ADDRESS_LOWER. */
svc_gl_cb_sel_bc =
(svc_gl_cb_sel_bc &
- 0xffffffffULL) |
- ((u64)w << 32);
+ ~0xffffffffULL) |
+ (u64)w;
svc_gl_cb_sel_seen = true;
break;
case 0x238cu:
@@ -18333,9 +18385,10 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object,
*/
if (svc_gl_cb_diag_log < SVC_GL_CB_DIAG_MAX) {
svc_gl_cb_diag_log++;
- pr_info("vgsp-sema: sema-gl: CB-DIAG h=0x%x push=0x%llx len=%u hdr=%u run=%u over=%u match=%u[3800=%u 39c8=%u 39d0=%u 2380=%u 238c=%u 2390=%u 3460=%u] b3800first=0x%x words=%u off=0x%x base=0x%llx valid=%u mvp=%u m80=%08x %08x %08x %08x row3=%08x %08x %08x %08x\n",
+ pr_info("vgsp-sema: sema-gl: CB-DIAG h=0x%x push=0x%llx len=%u hdr=%u run=%u over=%u match=%u[3800=%u 39c8=%u 39d0=%u 2380=%u 238c=%u 2390=%u 3460=%u] subch=%u b3800first=0x%x words=%u off=0x%x base=0x%llx valid=%u mvp=%u m80=%08x %08x %08x %08x row3=%08x %08x %08x %08x\n",
h_object, push_va, len, nhdr, runs, nover, nmatch,
n3800, n39c8, n39d0, n2380, n238c, n2390, n3460,
+ subch_seen == 0xffffffffu ? 0u : subch_seen,
b3800_first, words, svc_gl_cb_off, svc_gl_cb_img_base,
svc_gl_cb_img_valid ? 1u : 0u,
svc_gl_cb_mvp_ok(svc_gl_cb_img) ? 1u : 0u,