summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_display_engine.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_display_engine.c')
-rw-r--r--kernel/gsp_display_engine.c30
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) {