diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 75 |
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, |
