diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 233 |
1 files changed, 226 insertions, 7 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 12c6afd..079fce4 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -16345,6 +16345,9 @@ static u64 svc_gl_cb_sel_bc; static bool svc_gl_cb_sel_seen; static u32 svc_gl_cb_scan_log; static u32 svc_gl_cb_apply_log; +/* CB-DIAG (2026-11-10): bounded per-push capture summary. */ +static u32 svc_gl_cb_diag_log; +#define SVC_GL_CB_DIAG_MAX 48u #define SVC_GL_CB_IMG_LIMIT SEMA_PAGE_SIZE @@ -16365,6 +16368,11 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object, u64 base = 0; bool dirty = false; u32 i; + /* CB-DIAG counters */ + u32 nhdr = 0, nover = 0, nmatch = 0; + u32 n3800 = 0, n39c8 = 0, n39d0 = 0, n2380 = 0; + u32 n238c = 0, n2390 = 0, n3460 = 0; + u32 b3800_first = 0xffffffffu; (void)vgpu; if ((h_object & 0xfffff000u) != 0xbeef0000u || !buf || len < 16u) @@ -16382,6 +16390,7 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object, u32 hdr, op, cnt, addr, w; memcpy(&hdr, buf + off, 4); + nhdr++; if (!hdr) { off += 4u; continue; @@ -16396,6 +16405,17 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object, if (op == 4u) { /* IMMD: 13-bit payload; offset/selector only. */ w = (hdr >> 16) & 0x1fffu; + if (addr == 0x3800u) { + n3800++; + if (b3800_first == 0xffffffffu) + b3800_first = w << 2; + } else if (addr == 0x238cu) { + n238c++; + } else if (addr == 0x2384u || addr == 0x2388u) { + n2380++; + } else if (addr == 0x3460u) { + n3460++; + } if (addr == 0x3460u) { base = (u64)w << 8; if (base && base != svc_gl_cb_img_base) @@ -16442,9 +16462,23 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object, * later, exactly like svc_scratch18_watch does, so the * constant stream after the data block is still found. */ + nover++; off += 4u; continue; } + nmatch++; + if (addr == 0x238cu) + n238c++; + else if (addr >= 0x2380u && addr <= 0x238cu) + n2380++; + else if (addr == 0x3460u) + n3460++; + else if (addr == 0x39c8u) + n39c8++; + else if (addr == 0x39d0u) + n39d0++; + else if (addr >= 0x2390u && addr < 0x2390u + 0x1000u) + n2390++; if (addr == 0x238cu) { memcpy(&w, buf + off + 4u, 4); svc_gl_cb_off = w; @@ -16557,6 +16591,57 @@ static void svc_gl_cb_upload_scan(struct nv_vgpu_device *vgpu, u32 h_object, } off += 4u + cnt * 4u; } + /* + * CB-DIAG (2026-11-10): one bounded line per beef push so a live run + * shows whether the MVP upload reaches the image at byte 0x80. If + * n3800>0 but b3800_first>=0x1000, the client uploads its transform + * at a CB offset this 4 KB image cannot hold; if n39c8/n2390==0 the + * upload-bearing push was never decoded; if m80 is non-zero but + * mvp=0 the captured block is not the projection. + */ + 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", + h_object, push_va, len, nhdr, runs, nover, nmatch, + n3800, n39c8, n39d0, n2380, n238c, n2390, n3460, + 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, + get_unaligned_le32(svc_gl_cb_img + 0x80), + get_unaligned_le32(svc_gl_cb_img + 0x84), + get_unaligned_le32(svc_gl_cb_img + 0x88), + get_unaligned_le32(svc_gl_cb_img + 0x8c), + get_unaligned_le32(svc_gl_cb_img + 0xb0), + get_unaligned_le32(svc_gl_cb_img + 0xb4), + get_unaligned_le32(svc_gl_cb_img + 0xb8), + get_unaligned_le32(svc_gl_cb_img + 0xbc)); + { + u32 nz = 0, q; + + for (q = 0; q < 0x100u; q++) + if (svc_gl_cb_img[q]) + nz++; + pr_info("vgsp-sema: sema-gl: CB-DIAG2 h=0x%x img[00..1c]=%08x %08x %08x %08x %08x %08x %08x %08x img[90..ac]=%08x %08x %08x %08x %08x %08x %08x %08x nz=0x%x\n", + h_object, + get_unaligned_le32(svc_gl_cb_img + 0x00), + get_unaligned_le32(svc_gl_cb_img + 0x04), + get_unaligned_le32(svc_gl_cb_img + 0x08), + get_unaligned_le32(svc_gl_cb_img + 0x0c), + get_unaligned_le32(svc_gl_cb_img + 0x10), + get_unaligned_le32(svc_gl_cb_img + 0x14), + get_unaligned_le32(svc_gl_cb_img + 0x18), + get_unaligned_le32(svc_gl_cb_img + 0x1c), + get_unaligned_le32(svc_gl_cb_img + 0x90), + get_unaligned_le32(svc_gl_cb_img + 0x94), + get_unaligned_le32(svc_gl_cb_img + 0x98), + get_unaligned_le32(svc_gl_cb_img + 0x9c), + get_unaligned_le32(svc_gl_cb_img + 0xa0), + get_unaligned_le32(svc_gl_cb_img + 0xa4), + get_unaligned_le32(svc_gl_cb_img + 0xa8), + get_unaligned_le32(svc_gl_cb_img + 0xac), + nz); + } + } if (!dirty || !words) return; svc_gl_cb_img_words += words; @@ -24730,7 +24815,18 @@ static bool svc_fb_userd_pristine_scan(struct nv_vgpu_device *vgpu, memchr_inv(base + off + SVC_USERD_GP_GET + 8, 0, 0x100 - SVC_USERD_GP_GET - 8)) continue; - if (svc_fb_claim_foreign(vgpu, ch->h_object, 0, off)) + /* + * X-DMA-FIX: pass the candidate offset as both ring and USERD. + * The old (0, off) form could not match a live CE rank's + * convention ring (ring_off == conv), but it also made every + * later pristine scan foreign against the first pristine + * adopter (which stores ring_off=0): (0 == 0) matched the + * ring_off check unconditionally. Matching the actual offset + * against both stored fields keeps the CE convention + * reservation and the one-owner-per-block rule while allowing + * a second GR channel its own block. + */ + if (svc_fb_claim_foreign(vgpu, ch->h_object, off, off)) continue; *off_out = off; *put_out = hp; @@ -24962,6 +25058,20 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch, { u64 cand[8]; u32 as[8], nc = 0, i; + /* + * X-DMA-FIX (2026-11-10): "translated" is not "validated". svc_lookup + * can answer from a stale pin or a foreign VAS with a page whose + * GPFIFO entries are zero/foreign; the r496b FB sweep then rejects + * every candidate while ring_pa != 0, and the old !ring_pa pristine + * gate skipped the fallback in exactly that state. The channel then + * stayed without a USERD, the pump never wrote GP_GET, and the Xorg + * DDX pushbuffer NOP test timed out (10 s) -> "Failed to initialize + * DMA". Track whether the sweep actually ran and whether any entry + * decoded into this channel's push window so the pristine scan can + * still run for a resolved-but-unvalidated ring. + */ + bool ring_entry_ok = false; /* a ring entry decoded in this sweep */ + bool ring_sweep_ran = false; /* the r496b FB sweep ran this call */ int ring_alt = ring_ap == SVC_APERTURE_FB ? SVC_APERTURE_SYS : SVC_APERTURE_FB; @@ -25392,6 +25502,7 @@ ce_fb_scan: ch->fb_userd_scan_at = jiffies; ch->fb_userd_scan_n++; ch->userd_scans++; + ring_sweep_ran = true; lim = min_t(u64, svc_fb_shadow_size(vgpu), 0x20000000ULL); if (base && lim) { for (off = 0; off + 0xa0 <= lim; off += 0x200) { @@ -25507,6 +25618,16 @@ ce_fb_scan: rklen = elen; break; } + /* + * X-DMA-FIX: an entry that decodes into + * this channel's push window proves the + * resolved page really carries this + * channel's GPFIFO. This is the only + * "ring validated" signal the pristine + * gate below may use; wused only says the + * walk fallback was needed. + */ + ring_entry_ok = true; if (ch->engine_type && k == (u32)((hp - 1) % ch->gpfifo_entries)) @@ -25632,17 +25753,34 @@ ce_fb_scan: * starts iterating entries as soon as the ring walk lands, inside * the driver's 10 s window. */ - if (!ch->engine_type && !ring_pa && + /* + * X-DMA-FIX (2026-11-10): run the pristine scan when the ring is not + * translated (!ring_pa, as before) OR when the r496b sweep ran this + * call on a resolved ring but could not validate a single entry + * (ring_sweep_ran && !ring_entry_ok). A RAM-anchored ring + * (gr_ram_ring) keeps its own guest-RAM USERD scan and is excluded. + */ + if (!ch->engine_type && + (!ring_pa || + (ring_sweep_ran && !ring_entry_ok && !ch->gr_ram_ring)) && ch->fb_userd_scan_n < 512 && - (!ch->fb_userd_scan_at || + (!ch->fb_userd_scan_at || ring_sweep_ran || time_after_eq(jiffies, (unsigned long)ch->fb_userd_scan_at + msecs_to_jiffies(25)))) { u64 off = 0; u32 p = 0, g = 0; - ch->fb_userd_scan_at = jiffies; - ch->fb_userd_scan_n++; + /* + * X-DMA-FIX: the sweep above already spent this call's scan + * slot. Counting the combined call twice would halve the + * 512-scan (12.8 s at 25 ms) window the X 10 s DMA test + * relies on. Only a standalone pristine scan pays here. + */ + if (!ring_sweep_ran) { + ch->fb_userd_scan_at = jiffies; + ch->fb_userd_scan_n++; + } if (svc_fb_userd_pristine_scan(vgpu, ch, &off, &p, &g)) { ch->userd_pa = off; ch->userd_as = SVC_APERTURE_FB; @@ -25650,9 +25788,11 @@ ce_fb_scan: svc_fb_claim_add(ch->h_object, 0, off); *put = p; *get = g; - pr_info("sema-chan: GR USERD h=0x%x rank=%u found by pristine-FB scan at fb 0x%llx (put=%u get=%u; ring 0x%llx not translated yet)\n", + pr_info("sema-chan: GR USERD h=0x%x rank=%u found by pristine-FB scan at fb 0x%llx (put=%u get=%u; ring va 0x%llx pa 0x%llx %s)\n", ch->h_object, ch->gr_index, off, p, g, - ch->gpfifo_va); + ch->gpfifo_va, ring_pa, + ring_pa ? "resolved but not validated" + : "not translated yet"); return 0; } } @@ -29161,6 +29301,64 @@ static void svc_xvas_pdb_discover(struct nv_vgpu_device *vgpu, u64 ring_va, } } +/* + * X-DMA-FIX (2026-11-10): register the channel's own parked + * COPY_SERVER_PDES candidate as soon as a pump pass can content-validate it + * against this channel's GPFIFO, instead of waiting for the age-out. The + * existing verifier is anchored to the current ring_pa; when the lookup + * answered a stale/foreign page that pair is wrong and the candidate never + * matches until the 1000 ms age-out registers it UNVERIFIED (r1585: first + * USERD sweep at +15 ms, age-out at +1.36 s, X's DMA test window 10 s). + * Anchor on the channel's own gpfifo_va and its entry 0 content instead. + */ +static void svc_chan_vas_candidate_promote(struct nv_vgpu_device *vgpu, + struct svc_channel *ch) +{ + u32 h = ch->h_vaspace; + int i; + + if (!h || svc_vaspace_known(h) || !ch->gpfifo_va || + ch->gpfifo_entries < 2) + return; + for (i = 0; i < SVC_VAS_CAND_MAX; i++) { + u64 wpa = 0; + int wap = SVC_APERTURE_SYS; + u8 e[SVC_GPFIFO_ENTRY_SIZE]; + u32 e0 = 0, e1 = 0, len; + u64 eva; + struct sema_vaspace_desc d; + + if (!svc_vas_cand[i].valid || svc_vas_cand[i].h_vaspace != h) + continue; + if (svc_gmmu_walk(vgpu, svc_vas_cand[i].pdb, + svc_vas_cand[i].entries, + ch->gpfifo_va & ~(u64)(SEMA_PAGE_SIZE - 1), + svc_vas_cand[i].vidmem ? SVC_APERTURE_FB + : SVC_APERTURE_SYS, + &wpa, &wap, false)) + continue; + if (svc_read_ap(vgpu, wpa, wap, e, sizeof(e))) + continue; + memcpy(&e0, e, 4); + memcpy(&e1, e + 4, 4); + eva = ((u64)(e1 & 0xff) << 32) | (u64)(e0 & 0xfffffffc); + len = ((e1 >> 10) & 0x1fffff) << 2; + if (!eva || len < 4 || len > 0x10000 || + !svc_gr_entry_win_ok(ch->gpfifo_va, eva)) + continue; + memset(&d, 0, sizeof(d)); + d.h_vaspace = h; + d.pdb = svc_vas_cand[i].pdb; + d.num_entries = svc_vas_cand[i].entries; + d.b_vidmem = svc_vas_cand[i].vidmem; + gsp_sema_service_vaspace_add(&d); + svc_vas_cand[i].valid = false; + pr_info("sema-svc: VAS 0x%x registered at channel 0x%x turn (parked candidate content-validated: gpfifo 0x%llx entry0 va=0x%llx len=%u)\n", + h, ch->h_object, ch->gpfifo_va, eva, len); + return; + } +} + static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu, struct svc_channel *ch) { @@ -40857,7 +41055,24 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) * entries through this channel's VAS. */ svc_cur_vas = ch->h_vaspace; + /* + * CONT.395/X-DMA-FIX: hVASpace==0 is the driver's "attach to + * the TSG address space". The GR client channel (0xbeef0100) + * publishes vas=0 while its CE siblings (0xbeef0101/0102) carry + * the real VAS 0xbeef0300; without this fallback svc_lookup + * cannot resolve the GR ring (ring_pa=0) and the beef draw + * stream is never decoded, so the fixed-CB scan never runs. + */ + if (!svc_cur_vas) + svc_cur_vas = svc_channel_owner_vas(vgpu, ch->h_object); + /* + * X-DMA-FIX: the channel's own parked VAS must be usable before + * the first ring lookup/USERD sweep; the age-out registers it + * only after the X client's 10 s window. Content-gate it + * against this channel's GPFIFO. + */ + svc_chan_vas_candidate_promote(vgpu, ch); svc_ring_autopin(vgpu, ch); /* * SESSION 153-CONTINUED-75: heal a GR ring whose translation @@ -41619,6 +41834,10 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) * svc_chanvas_lookup). Refreshed per channel turn; a channel * without a known VAS clears it back to the old chain. */ svc_cur_vas = ch->h_vaspace; + /* CONT.395: hVASpace==0 attaches to the TSG VAS - use the + * sibling/owner VAS so releases resolve for the GR client. */ + if (!svc_cur_vas) + svc_cur_vas = svc_channel_owner_vas(vgpu, ch->h_object); /* * C4 (GAP-1 H1): the GR walk witness - does put advance, and |
