Skip to content

Commit 80cf9a8

Browse files
vsyrjalarodrigovivi
authored andcommitted
drm/i915: Disallow plane x+w>stride on ilk+ with X-tiling
ilk+ planes get notably unhappy when the plane x+w exceeds the stride. This wasn't a problem previously because we always aligned SURF to the closest tile boundary so the x offset never got particularly large. But now with async flips we have to align to 256KiB instead and thus this becomes a real issue. On ilk/snb/ivb it looks like the accesses just wrap early to the next tile row when scanout goes past the SURF+n*stride boundary, hsw/bdw suffer more heavily and start to underrun constantly. i965/g4x appear to be immune. vlv/chv I've not yet checked. Let's borrow another trick from the skl+ code and search backwards for a better SURF offset in the hopes of getting the x offset below the limit. IIRC when I ran into a similar issue on skl years ago it was causing the hardware to fall over pretty hard as well. And let's be consistent and include i965/g4x in the check as well, just in case I just got super lucky somehow when I wasn't able to reproduce the issue. Not that it really matters since we still use 4k SURF alignment for i965/g4x anyway. Fixes: 6ede6b0 ("drm/i915: Implement async flips for vlv/chv") Fixes: 4bb1805 ("drm/i915: Implement async flip for ilk/snb") Fixes: 2a636e2 ("drm/i915: Implement async flip for ivb/hsw") Fixes: cda195f ("drm/i915: Implement async flips for bdw") Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210209021918.16234-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> (cherry picked from commit 59fb821) Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> [Rodrigo also exported some functions from intel_display.c during backport]
1 parent 7a6c624 commit 80cf9a8

3 files changed

Lines changed: 39 additions & 6 deletions

File tree

drivers/gpu/drm/i915/display/i9xx_plane.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,33 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
255255
else
256256
offset = 0;
257257

258+
/*
259+
* When using an X-tiled surface the plane starts to
260+
* misbehave if the x offset + width exceeds the stride.
261+
* hsw/bdw: underrun galore
262+
* ilk/snb/ivb: wrap to the next tile row mid scanout
263+
* i965/g4x: so far appear immune to this
264+
* vlv/chv: TODO check
265+
*
266+
* Linear surfaces seem to work just fine, even on hsw/bdw
267+
* despite them not using the linear offset anymore.
268+
*/
269+
if (INTEL_GEN(dev_priv) >= 4 && fb->modifier == I915_FORMAT_MOD_X_TILED) {
270+
u32 alignment = intel_surf_alignment(fb, 0);
271+
int cpp = fb->format->cpp[0];
272+
273+
while ((src_x + src_w) * cpp > plane_state->color_plane[0].stride) {
274+
if (offset == 0) {
275+
drm_dbg_kms(&dev_priv->drm,
276+
"Unable to find suitable display surface offset due to X-tiling\n");
277+
return -EINVAL;
278+
}
279+
280+
offset = intel_plane_adjust_aligned_offset(&src_x, &src_y, plane_state, 0,
281+
offset, offset - alignment);
282+
}
283+
}
284+
258285
/*
259286
* Put the final coordinates back so that the src
260287
* coordinate checks will see the right values.

drivers/gpu/drm/i915/display/intel_display.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,8 +1322,8 @@ static bool has_async_flips(struct drm_i915_private *i915)
13221322
return INTEL_GEN(i915) >= 5;
13231323
}
13241324

1325-
static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
1326-
int color_plane)
1325+
unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
1326+
int color_plane)
13271327
{
13281328
struct drm_i915_private *dev_priv = to_i915(fb->dev);
13291329

@@ -1590,10 +1590,10 @@ static u32 intel_adjust_aligned_offset(int *x, int *y,
15901590
* Adjust the tile offset by moving the difference into
15911591
* the x/y offsets.
15921592
*/
1593-
static u32 intel_plane_adjust_aligned_offset(int *x, int *y,
1594-
const struct intel_plane_state *state,
1595-
int color_plane,
1596-
u32 old_offset, u32 new_offset)
1593+
u32 intel_plane_adjust_aligned_offset(int *x, int *y,
1594+
const struct intel_plane_state *state,
1595+
int color_plane,
1596+
u32 old_offset, u32 new_offset)
15971597
{
15981598
return intel_adjust_aligned_offset(x, y, state->hw.fb, color_plane,
15991599
state->hw.rotation,

drivers/gpu/drm/i915/display/intel_display.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,12 @@ void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state);
653653
struct intel_encoder *
654654
intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
655655
const struct intel_crtc_state *crtc_state);
656+
unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
657+
int color_plane);
658+
u32 intel_plane_adjust_aligned_offset(int *x, int *y,
659+
const struct intel_plane_state *state,
660+
int color_plane,
661+
u32 old_offset, u32 new_offset);
656662

657663
/* modesetting */
658664
void intel_modeset_init_hw(struct drm_i915_private *i915);

0 commit comments

Comments
 (0)