diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-08 06:39:50 -0500 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-08 06:39:50 -0500 |
| commit | cfa2bf216065c87a185e83a8bf38a6c5dd5788c8 (patch) | |
| tree | 58495ecf023b18f990cb503bb5fb160b622bb438 | |
| parent | 0bfd7a693a9b59def9e1494d34b61794ae04930d (diff) | |
| download | open-iov-cfa2bf216065c87a185e83a8bf38a6c5dd5788c8.tar.gz open-iov-cfa2bf216065c87a185e83a8bf38a6c5dd5788c8.zip | |
vgsp-disp: never publish GET past PUT; bounded no-parse push dump
r1630: the window channel's first push read returned unparseable bytes
(0 methods) and the parser walked off the 4 KB ring, publishing
GET=0x1000 while PUT stayed 0x4e4. nvidia-modeset then wedged in
'Error while waiting for GPU progress', Xorg never started and glxinfo/
GZDoom never reached the GL path.
Only consume a segment that parses exactly to the driver's PUT. On a
short/invalid read, leave consumed unchanged: the pump retries next
pass (which also covers a ring the guest kicked before its content is
visible) and GET can never move past PUT. Dump the head of an
unparseable segment (bounded, disp_dbg) to name what the ring holds.
Reset dump budgets per mdev cleanup so each boot keeps its diagnostics.
| -rw-r--r-- | kernel/gsp_display_engine.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/kernel/gsp_display_engine.c b/kernel/gsp_display_engine.c index c2fab96..5109245 100644 --- a/kernel/gsp_display_engine.c +++ b/kernel/gsp_display_engine.c @@ -972,6 +972,32 @@ static void gsp_disp_run(struct nv_vgpu_device *vgpu, struct gsp_disp_chan *ch, } } + /* + * Only publish a read pointer when the segment parsed through to the + * driver's PUT. A segment that runs off the 4 KB ring (unwritten or + * not-yet-visible content) or hits misaligned data must NOT consume + * anything: publishing GET past PUT wedged nvidia-modeset on the + * window channel (r1630: GET=0x1000, "Error while waiting for GPU + * progress"). Leaving consumed unchanged also retries next pass, + * which covers a ring the guest has kicked but not yet flushed. + */ + if (off != put) { + if (gsp_disp_dbg && disp.push_dumps < 8) { + u32 d, shown = 16; + + disp.push_dumps++; + pr_info("h=0x%x push-noparse 0x%x..0x%x (consumed stays 0x%x) head:", + ch->hclass, start, put, ch->consumed); + if (put > start && put - start < shown) + shown = put - start; + for (d = 0; d < shown; d++) + pr_cont(" %08x", + *(u32 *)(disp.pbuf + start + 4 * d)); + pr_cont("\n"); + } + return; + } + ch->consumed = off; ch->last_put = put; if (gsp_disp_dbg && off != start) @@ -1111,6 +1137,10 @@ void gsp_disp_engine_vgpu_cleanup(struct nv_vgpu_device *vgpu) unsigned long flags; int i; + /* Fresh diagnostic budgets for the next mdev/boot. */ + disp.push_dumps = 0; + disp.im_logs = 0; + spin_lock_irqsave(&disp.lock, flags); for (i = 0; i < GSP_DISP_MAX_CHANNELS; i++) { if (disp.ch[i].valid && disp.ch[i].vgpu == vgpu) { |
