From ab393b15abac5b6c0790bb4c4fd86bc62c531bf4 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 28 Sep 2026 09:23:51 -0400 Subject: sema: GR ring autopin must not trust an early base or a pre-existing pin Two failure modes kept every GR channel dark despite the ring layout being known: - The CE region size was latched on the first autopin attempt, which can run before all CE channels are registered; a too-small base then points every GR candidate at a chunk whose entry 0 is zeros, and it stays wrong for the life of the boot. Recompute the base from the live CE ranks on every pass. - An existing pin for a ring VA (e.g. from a convention guess) made the autopin mark the rank done without validating the ring - a wrong USERD is then never corrected. Validate the candidate chunk (entry 0 decode + USERD put/get) first and only fall back to trusting an existing pin when the chunk does not validate; on success overwrite the pin. Also log one diagnostic line per GR rank when the chunk does not validate yet, so a silent autopin failure is visible in dmesg. Live: fresh boot, no manual ring pins - 20/20 GR channels auto-pinned (correct USERD 0x142000 + 0x3000*i) and ran entry 0 (get=1 sub=1) once the push pages were bridged. --- kernel/gsp_sema_service.c | 105 +++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 43 deletions(-) (limited to 'kernel') diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 7f39209..bf6bb01 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -2779,13 +2779,15 @@ static int svc_chan_entry0(struct nv_vgpu_device *vgpu, struct svc_channel *ch, bool gsp_sema_gr_rings = true; +static unsigned long svc_gr_ring_tried; /* ranks that got a diagnostic line */ + static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu, struct svc_channel *ch) { - u64 pa; - int ap = SVC_APERTURE_SYS; + u64 base, pa, pin_pa, va = 0; + int pin_ap = SVC_APERTURE_SYS; u8 e[SVC_GPFIFO_ENTRY_SIZE]; - u32 e0, e1, va, len, put = 0, get = 0; + u32 e0 = 0, e1 = 0, len = 0, put = 0, get = 0, max_ce = 0; unsigned long flags; int k; @@ -2795,52 +2797,69 @@ static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu, return; if (test_bit(ch->gr_index, &svc_gr_ring_done)) return; - if (!svc_pin_lookup(ch->gpfifo_va, &pa, &ap)) { - /* Already translated (bridge/manual pin): nothing to do. */ - set_bit(ch->gr_index, &svc_gr_ring_done); - svc_ring_n++; - return; - } - if (!svc_gr_ring_base) { - u32 max_ce = 0; + /* + * Recompute the CE region size on every attempt. An early attempt can + * run before all CE channels are registered; a latched-too-early base + * would point at the wrong chunk forever. + */ + spin_lock_irqsave(&svc.chan_lock, flags); + for (k = 0; k < SVC_MAX_CHANNELS; k++) + if (svc.chan[k].valid && svc.chan[k].engine_type && + svc.chan[k].ce_index + 1 > max_ce) + max_ce = svc.chan[k].ce_index + 1; + spin_unlock_irqrestore(&svc.chan_lock, flags); + if (!max_ce) + return; /* wait until the CE channels are known */ - spin_lock_irqsave(&svc.chan_lock, flags); - for (k = 0; k < SVC_MAX_CHANNELS; k++) - if (svc.chan[k].valid && svc.chan[k].engine_type && - svc.chan[k].ce_index + 1 > max_ce) - max_ce = svc.chan[k].ce_index + 1; - spin_unlock_irqrestore(&svc.chan_lock, flags); - if (!max_ce) - return; /* wait until the CE channels are known */ - svc_gr_ring_base = SVC_CE_RING_FB_BASE + - SVC_CE_RING_FB_STRIDE * max_ce; + base = SVC_CE_RING_FB_BASE + SVC_CE_RING_FB_STRIDE * max_ce; + pa = base + SVC_GR_RING_STRIDE * ch->gr_index; + + /* + * Validate the candidate chunk before trusting anything else: an + * existing pin may come from a convention guess that is wrong for + * this window (observed: a bogus vidmem offset for a GR ring VA, + * which made the old "already translated" shortcut skip the ring + * with a wrong USERD forever). + */ + if (!svc_read_ap(vgpu, pa, SVC_APERTURE_FB, e, sizeof(e))) { + memcpy(&e0, e, 4); + memcpy(&e1, e + 4, 4); + va = ((u64)(e1 & 0xff) << 32) | (u64)(e0 & 0xfffffffc); + len = ((e1 >> 10) & 0x1fffff) << 2; + if (!(va & 0xfffff) && va >= SEMA_VA_LO && va < SEMA_VA_HI && + len >= 4 && len <= 0x10000 && + !svc_userd_probe(vgpu, pa + SVC_GR_USERD_OFF, + SVC_APERTURE_FB, ch->gpfifo_entries, + &put, &get)) { + svc_pin_store(ch->gpfifo_va, pa, SVC_APERTURE_FB); + svc_lat_store(ch->gpfifo_va, pa, SVC_APERTURE_FB); + ch->userd_pa = pa + SVC_GR_USERD_OFF; + ch->userd_as = SVC_APERTURE_FB; + ch->userd_ok = true; + svc_gr_ring_base = base; + set_bit(ch->gr_index, &svc_gr_ring_done); + svc_ring_n++; + pr_info("sema-chan: auto-pinned GR ring h=0x%x rank=%u va=0x%llx -> fb 0x%llx (entry0 va=0x%llx len=%u put=%u get=%u)\n", + ch->h_object, ch->gr_index, ch->gpfifo_va, pa, + va, len, put, get); + return; + } } - pa = svc_gr_ring_base + SVC_GR_RING_STRIDE * ch->gr_index; - if (svc_read_ap(vgpu, pa, SVC_APERTURE_FB, e, sizeof(e))) - return; - memcpy(&e0, e, 4); - memcpy(&e1, e + 4, 4); - va = ((u64)(e1 & 0xff) << 32) | (u64)(e0 & 0xfffffffc); - len = ((e1 >> 10) & 0x1fffff) << 2; - if ((va & 0xfffff) || va < SEMA_VA_LO || va >= SEMA_VA_HI || - len < 4 || len > 0x10000) - return; - if (svc_userd_probe(vgpu, pa + SVC_GR_USERD_OFF, SVC_APERTURE_FB, - ch->gpfifo_entries, &put, &get)) + /* + * The candidate chunk did not validate. If another source already + * translates this ring VA (bridge or manual pin), trust it. + */ + if (!svc_pin_lookup(ch->gpfifo_va, &pin_pa, &pin_ap)) { + set_bit(ch->gr_index, &svc_gr_ring_done); + svc_ring_n++; return; + } - svc_pin_store(ch->gpfifo_va, pa, SVC_APERTURE_FB); - svc_lat_store(ch->gpfifo_va, pa, SVC_APERTURE_FB); - ch->userd_pa = pa + SVC_GR_USERD_OFF; - ch->userd_as = SVC_APERTURE_FB; - ch->userd_ok = true; - set_bit(ch->gr_index, &svc_gr_ring_done); - svc_ring_n++; - pr_info("sema-chan: auto-pinned GR ring h=0x%x rank=%u va=0x%llx -> fb 0x%llx (entry0 va=0x%llx len=%u put=%u get=%u)\n", - ch->h_object, ch->gr_index, ch->gpfifo_va, pa, va, len, put, - get); + if (!test_and_set_bit(ch->gr_index, &svc_gr_ring_tried)) + pr_info("sema-chan: GR ring h=0x%x rank=%u not at fb 0x%llx yet (entry e0=0x%x e1=0x%x va=0x%llx len=%u)\n", + ch->h_object, ch->gr_index, pa, e0, e1, va, len); } static void svc_ring_autopin(struct nv_vgpu_device *vgpu, -- cgit v1.2.3