From 4d4bb3ca0f8c23b8a8bd9893a0f0b4ebbfddd7a8 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 22 Oct 2026 18:03:07 -0400 Subject: r496e the X NOP push: all-zero accepted on content-scanned channels; no capture holds for their entries The driver's __nvPushTestPushBuffer writes one zero dword (NVA06F_DMA_NOP) and waits for GP_GET to follow GP_PUT. The method-stream plausibility gate rejects an all-zero buffer (it parses as zero methods), so the entry fell into the unreadable/rescue path and the GR no-capture hold - the DMA sanity test could never pass. For channels whose ring was found by the RAM content scan (kernel-RM sysmem 3D channels), model them as consume-and-apply- releases: accept an all-zero NOP push, and skip the no-capture hold (these pushes are not compute launches; holding them 6 s per entry cannot help). --- kernel/gsp_sema_service.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index c8987b7..d20ad92 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -440,6 +440,16 @@ struct svc_channel { u64 gr_ram_cursor; /* resume point of the content scan */ u8 gr_ram_passes; /* slices walked so far */ bool gr_ram_logged; /* one discovery line per channel */ + /* + * r496e: true when the ring was found by the RAM content scan (a + * kernel-RM sysmem channel - the X/GL 3D channel). Such a channel's + * pushes are 2D/3D method streams the emulation does not execute; + * the correct model is consume-and-apply-releases: no QMD capture, + * no launch forward, no no-capture hold. Also allows an all-zero + * NOP push (the driver's pushbuffer sanity test writes exactly one + * zero dword) to be consumed as the no-op it is. + */ + bool gr_ram_ring; /* * r496b: the FB-scan USERD (see svc_userd_fb_scan). Latched when the * registered/ring-derived candidates all fail; the scan validates the @@ -14575,8 +14585,33 @@ static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu, SVC_APERTURE_SYS); } ch->gr_ram_logged = true; + ch->gr_ram_ring = true; set_bit(ch->gr_index, &svc_gr_ring_done); svc_ring_n++; + /* + * Persist the latch immediately: a later stalled + * path in this pass may `continue` past the + * end-of-pass write-back, and the next pass's + * snapshot must carry gr_ram_ring (the zero-NOP + * exception and the no-capture-hold skip key on + * it). + */ + { + unsigned long flags2; + int i2; + + spin_lock_irqsave(&svc.chan_lock, flags2); + for (i2 = 0; i2 < SVC_MAX_CHANNELS; i2++) + if (svc.chan[i2].valid && + svc.chan[i2].vgpu == vgpu && + svc.chan[i2].h_object == + ch->h_object) { + svc.chan[i2].gr_ram_ring = true; + svc.chan[i2].gr_ram_logged = true; + break; + } + spin_unlock_irqrestore(&svc.chan_lock, flags2); + } pr_info("sema-chan: GR ring h=0x%x rank=%u found by RAM content scan va=0x%llx -> pa=0x%llx (allocation window pinned; entry/push reads resolve through it)\n", ch->h_object, ch->gr_index, ch->gpfifo_va, hit_pa); @@ -21163,7 +21198,20 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) injected = (svc_ipin_lookup(va, &ipa, &iap) == 0); - if (!svc_method_stream_plausible(pb, len)) { + /* + * r496e: an all-zero push on a + * content-scanned-ring channel is the + * driver's NOP sanity push (one zero + * dword - NVA06F_DMA_NOP), not a bad + * translation: accept it and let the + * decode find no ops. + */ + bool zero_nop = ch->gr_ram_ring && + len >= 4 && + !memchr_inv(pb, 0, len); + + if (!svc_method_stream_plausible(pb, len) && + !zero_nop) { svc.false_trans++; if (injected) { u8 *fb = kmalloc(len, @@ -21982,6 +22030,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) jiffies; } if (gsp_sema_gr_nocap_hold_ms && + !ch->gr_ram_ring && time_before(jiffies, ch->gr_nocap_since + msecs_to_jiffies( @@ -22731,6 +22780,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) svc.chan[k].gr_ram_cursor = ch->gr_ram_cursor; svc.chan[k].gr_ram_passes = ch->gr_ram_passes; svc.chan[k].gr_ram_logged = ch->gr_ram_logged; + svc.chan[k].gr_ram_ring = ch->gr_ram_ring; svc.chan[k].userd_scans = ch->userd_scans; svc.chan[k].logged = ch->logged; svc.chan[k].logged_expected = ch->logged_expected; -- cgit v1.2.3