intel_dsb_gosub_align() aligns free_pos to a cacheline boundary
before emitting GOSUB, but zeroes the skipped bytes only when at most
two QW slots remain. Any larger gap stays between head and tail and is
fetched as DSB instructions.

A Panther Lake dump taken from a DSB idle timeout shows that gap: the
tail is 0x58, GOSUB is at 0x80, and the 40 bytes between them are
nonzero instead of NOP (opcode 0).

Zero every byte skipped by the existing alignment. Preserve the GOSUB
placement, which avoids cacheline QW slots 6 and 7 as required by
Wa_16024917128.

Fixes: 2c41d62f6fb1 ("drm/i915/dsb: Implement intel_dsb_gosub()")
Cc: [email protected] # v6.17+
Signed-off-by: Hanson Wang <[email protected]>
---
Hardware: Intel Core Ultra 5 336H (Panther Lake), 6.18-based kernel
Reboots:  7/100 DSB idle timeouts before this fix, 0/200 after
Build:    6.18 backport; both xe and i915 intel_dsb.o
Upstream: not built or booted
Reproducer: upstream intel_dsb_gosub_align(), buffer prefilled with
            0xa5. 5/8 cacheline positions missed NOPs before; 32/32
            pass after, including the 0x58 -> 0x80 gap from the dump
Limit:    these results do not show that every DSB or flip_done
          timeout has the same cause

 drivers/gpu/drm/i915/display/intel_dsb.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c 
b/drivers/gpu/drm/i915/display/intel_dsb.c
index d9a270362a82..b71e99ed8705 100644
--- a/drivers/gpu/drm/i915/display/intel_dsb.c
+++ b/drivers/gpu/drm/i915/display/intel_dsb.c
@@ -607,8 +607,13 @@ static void intel_dsb_gosub_align(struct intel_dsb *dsb)
        /*
         * Wa_16024917128
         * "Ensure GOSUB is not placed in cacheline QW slot 6 or 7 (numbered 
0-7)"
+        *
+        * free_pos always advances to the next cacheline, so the skipped
+        * bytes remain inside the programmed command range. Fill the whole
+        * gap with NOPs; clearing only slots 6 and 7 leaves a larger gap
+        * uninitialized.
         */
-       if (aligned_tail - tail <= 2 * 8)
+       if (aligned_tail > tail)
                dsb_buffer_fill(dsb, dsb->free_pos, 0, aligned_tail - tail);
 
        dsb->free_pos = aligned_tail / 4;
-- 
2.34.1

Reply via email to