Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: Fix two cursor duplication when using overlay

Our driver supports overlay planes, and as expected, some userspace
compositor takes advantage of these features. If the userspace is not
enabling the cursor, they can use multiple planes as they please.
Nevertheless, we start to have constraints when userspace tries to
enable hardware cursor with various planes. Basically, we cannot draw
the cursor at the same size and position on two separated pipes since it
uses extra bandwidth and DML only run with one cursor.

For those reasons, when we enable hardware cursor and multiple planes,
our driver should accept variations like the ones described below:

+-------------+ +--------------+
| +---------+ | | |
| |Primary | | | Primary |
| | | | | Overlay |
| +---------+ | | |
|Overlay | | |
+-------------+ +--------------+

In this scenario, we can have the desktop UI in the overlay and some
other framebuffer attached to the primary plane (e.g., video). However,
userspace needs to obey some rules and avoid scenarios like the ones
described below (when enabling hw cursor):

+--------+
|Overlay |
+-------------+ +-----+-------+ +-| |--+
| +--------+ | +--------+ | | +--------+ |
| |Overlay | | |Overlay | | | |
| | | | | | | | |
| +--------+ | +--------+ | | |
| Primary | | Primary | | Primary |
+-------------+ +-------------+ +-------------+

+-------------+ +-------------+
| +--------+ | Primary |
| |Overlay | | |
| | | | |
| +--------+ | +--------+ |
| Primary | | |Overlay | |
+-------------+ +-| |--+
+--------+

If the userspace violates some of the above scenarios, our driver needs
to reject the commit; otherwise, we can have unexpected behavior. Since
we don't have a proper driver validation for the above case, we can see
some problems like a duplicate cursor in applications that use multiple
planes. This commit fixes the cursor issue and others by adding adequate
verification for multiple planes.

Change since V1 (Harry and Sean):
- Remove cursor verification from the equation.

Cc: Louis Li <Ching-shih.Li@amd.com>
Cc: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Cc: Harry Wentland <Harry.Wentland@amd.com>
Cc: Hersen Wu <hersenxs.wu@amd.com>
Cc: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Rodrigo Siqueira and committed by
Alex Deucher
16e9b3e5 c83c4e19

+51
+51
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 9870 9870 } 9871 9871 #endif 9872 9872 9873 + static int validate_overlay(struct drm_atomic_state *state) 9874 + { 9875 + int i; 9876 + struct drm_plane *plane; 9877 + struct drm_plane_state *old_plane_state, *new_plane_state; 9878 + struct drm_plane_state *primary_state, *overlay_state = NULL; 9879 + 9880 + /* Check if primary plane is contained inside overlay */ 9881 + for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { 9882 + if (plane->type == DRM_PLANE_TYPE_OVERLAY) { 9883 + if (drm_atomic_plane_disabling(plane->state, new_plane_state)) 9884 + return 0; 9885 + 9886 + overlay_state = new_plane_state; 9887 + continue; 9888 + } 9889 + } 9890 + 9891 + /* check if we're making changes to the overlay plane */ 9892 + if (!overlay_state) 9893 + return 0; 9894 + 9895 + /* check if overlay plane is enabled */ 9896 + if (!overlay_state->crtc) 9897 + return 0; 9898 + 9899 + /* find the primary plane for the CRTC that the overlay is enabled on */ 9900 + primary_state = drm_atomic_get_plane_state(state, overlay_state->crtc->primary); 9901 + if (IS_ERR(primary_state)) 9902 + return PTR_ERR(primary_state); 9903 + 9904 + /* check if primary plane is enabled */ 9905 + if (!primary_state->crtc) 9906 + return 0; 9907 + 9908 + /* Perform the bounds check to ensure the overlay plane covers the primary */ 9909 + if (primary_state->crtc_x < overlay_state->crtc_x || 9910 + primary_state->crtc_y < overlay_state->crtc_y || 9911 + primary_state->crtc_x + primary_state->crtc_w > overlay_state->crtc_x + overlay_state->crtc_w || 9912 + primary_state->crtc_y + primary_state->crtc_h > overlay_state->crtc_y + overlay_state->crtc_h) { 9913 + DRM_DEBUG_ATOMIC("Overlay plane is enabled with hardware cursor but does not fully cover primary plane\n"); 9914 + return -EINVAL; 9915 + } 9916 + 9917 + return 0; 9918 + } 9919 + 9873 9920 /** 9874 9921 * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM. 9875 9922 * @dev: The DRM device ··· 10090 10043 if (ret) 10091 10044 goto fail; 10092 10045 } 10046 + 10047 + ret = validate_overlay(state); 10048 + if (ret) 10049 + goto fail; 10093 10050 10094 10051 /* Add new/modified planes */ 10095 10052 for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {