diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-09 14:45:12 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-09 14:45:12 -0400 |
| commit | 70ea49c667eb101b90730ed7a5077a7d7444c9ef (patch) | |
| tree | 474be81326cc61a0c6acfa7e6a5addbe88a7f21d | |
| parent | 64435b06a1973ae23b7be7cfa627ec416303ae85 (diff) | |
| download | open-iov-70ea49c667eb101b90730ed7a5077a7d7444c9ef.tar.gz open-iov-70ea49c667eb101b90730ed7a5077a7d7444c9ef.zip | |
vgsp-sema+guest-diag: fix CE USERD discovery for re-registered sessions (ISSUE-0002)
svc_chan_userd now prefers the layout-derived CE USERD
(ring_pa + 0x10000 in the ring aperture) and accepts it while idle, so
a second session cannot latch onto the registered pool-relative offset
when that alias holds a DIFFERENT rank's stale USERD: r40 c2 rank0 read
rank3's stale 1/1 at FB 0xf0000 and the pump never followed rank0's own
GP_PUT (guest GPUT mapping for gpFifoGpuVa proves ring+0x10000).
guest_pin_stream.va_to_pa drops translations outside the registered
guest-RAM windows so BAR1-phys addresses (0x70000xxxxx) are no longer
injected as SYS pins; r40 rank2's ring resolved to the bogus
pa=0x70000c0000 ap=SYS and read 66/66.
| -rw-r--r-- | kernel/gsp_sema_service.c | 30 | ||||
| -rw-r--r-- | tools/guest-diag/guest_pin_stream.py | 23 |
2 files changed, 53 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 3692246..309210d 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -7714,6 +7714,36 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch, int ring_alt = ring_ap == SVC_APERTURE_FB ? SVC_APERTURE_SYS : SVC_APERTURE_FB; + /* + * ISSUE-0002 (r40): prefer the layout-derived CE USERD and accept it + * while it is still idle. In a second session the registered userdMem + * offset (pool-relative, see below) aliases a DIFFERENT rank's real + * USERD whose stale put/get from the previous session won the + * coherent-pair probe while this channel's true block was still 0/0: + * c2 rank0 read rank3's stale 1/1 at FB 0xf0000 and the pump never + * followed rank0's own GP_PUT. The true CE USERD sits at + * ring + 0x10000 in the ring's aperture - confirmed by the guest + * CPU mapping of gpFifoGpuVa (GPU VA gpfifo+0x20000 maps to BAR + * offset ring+0x10000) and by every CE rank that resolved correctly. + * An idle (0/0) read is accepted here because the guest writes the + * block on the channel's first push; only unreadable or incoherent + * candidates fall through to the old list. + */ + if (ring_pa && ch->engine_type != 0) { + u32 p = 0, g = 0; + int rc = svc_userd_probe(vgpu, ring_pa + 0x10000, ring_ap, + ch->gpfifo_entries, &p, &g); + + if (rc == 0 || rc == -EAGAIN) { + ch->userd_pa = ring_pa + 0x10000; + ch->userd_as = ring_ap; + ch->userd_ok = true; + *put = p; + *get = g; + return 0; + } + } + if (ring_pa) { cand[nc] = ring_pa + 0x2000; as[nc++] = ring_ap; cand[nc] = ring_pa + 0x2000; as[nc++] = ring_alt; diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py index 14cd526..031271c 100644 --- a/tools/guest-diag/guest_pin_stream.py +++ b/tools/guest-diag/guest_pin_stream.py @@ -166,6 +166,9 @@ class Kcore: self._pa_cache[page] = 0 return None pa = e & 0x000FFFFFFFF000 + if not _is_ram_pa(pa): + self._pa_cache[page] = 0 + return None self._pa_cache[page] = pa return pa @@ -178,6 +181,26 @@ def is_gpu_va(v): return v and 0x120000000 <= v < 0x200000000 +# Guest-RAM windows registered with the host (debugfs gsp-phys-guest-ram): +# low 0..2 GiB and high 4..6 GiB. A CPU mapping of a channel block resolves +# through the guest page tables to a phys address in one of these windows +# when the backing is guest sysmem, but to a PCI BAR address (e.g. +# 0x70000xxxxx, the mdev BAR1 aperture) when the backing is the emulated +# vidmem. The host pin stream must only carry guest-RAM PAs: a BAR phys fed +# to sema_map_add as a "sysmem" pin poisoned the ring/USERD lookups (r40: +# rank2's ring resolved to pa=0x70000c0000 ap=SYS and read 66/66 garbage). +RAM_WINDOWS = ((0x0, 0x80000000), (0x100000000, 0x180000000)) + + +def _is_ram_pa(pa): + if not pa: + return False + for lo, hi in RAM_WINDOWS: + if lo <= pa < hi: + return True + return False + + def _is_gpu_va_wide(v): """GPU VAs above 0x200000000 are the GR share window; accept them too.""" return v and (is_gpu_va(v) or 0x200000000 <= v < 0x208000000) |
