drm/amd/display: check cursor FB is linear
authorSimon Ser <contact@emersion.fr>
Thu, 3 Dec 2020 20:19:41 +0000 (20:19 +0000)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 9 Dec 2020 04:02:16 +0000 (23:02 -0500)
Previously we accepted non-linear buffers for the cursor plane. This
results in bad output, DC validation failures and oops.

Make sure the FB uses a linear layout in the atomic check function.

The GFX8- check is inspired from ac_surface_set_bo_metadata in Mesa.
The GFX9+ check comes from convert_tiling_flags_to_modifier.

Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Simon Ser <contact@emersion.fr>
References: https://gitlab.freedesktop.org/drm/amd/-/issues/1390
Cc: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Harry Wentland <hwentlan@amd.com>
Cc: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

index fe16df8..0da49d2 100644 (file)
@@ -8980,7 +8980,10 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc,
                              struct drm_plane_state *new_plane_state,
                              struct drm_framebuffer *fb)
 {
+       struct amdgpu_device *adev = drm_to_adev(new_acrtc->base.dev);
+       struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb);
        unsigned int pitch;
+       bool linear;
 
        if (fb->width > new_acrtc->max_cursor_width ||
            fb->height > new_acrtc->max_cursor_height) {
@@ -9015,6 +9018,22 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc,
                return -EINVAL;
        }
 
+       /* Core DRM takes care of checking FB modifiers, so we only need to
+        * check tiling flags when the FB doesn't have a modifier. */
+       if (!(fb->flags & DRM_MODE_FB_MODIFIERS)) {
+               if (adev->family < AMDGPU_FAMILY_AI) {
+                       linear = AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) != DC_ARRAY_2D_TILED_THIN1 &&
+                                AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) != DC_ARRAY_1D_TILED_THIN1 &&
+                                AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0;
+               } else {
+                       linear = AMDGPU_TILING_GET(afb->tiling_flags, SWIZZLE_MODE) == 0;
+               }
+               if (!linear) {
+                       DRM_DEBUG_ATOMIC("Cursor FB not linear");
+                       return -EINVAL;
+               }
+       }
+
        return 0;
 }