| From 6b16cf7785a4200b1bddf4f70c9dda2efc49e278 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> |
| Date: Thu, 27 Oct 2016 14:54:31 +0900 |
| Subject: drm/radeon: Hide the HW cursor while it's out of bounds |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Michel Dänzer <michel.daenzer@amd.com> |
| |
| commit 6b16cf7785a4200b1bddf4f70c9dda2efc49e278 upstream. |
| |
| Fixes hangs in that case under some circumstances. |
| |
| v2: |
| * Only use non-0 x/yorigin if the cursor is (partially) outside of the |
| top/left edge of the total surface with AVIVO/DCE |
| |
| Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1000433 |
| Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> |
| Reviewed-by: Alex Deucher <alexander.deucher@amd.com> (v1) |
| Signed-off-by: Alex Deucher <alexander.deucher@amd.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/radeon/radeon_cursor.c | 60 +++++++++++++++++++++++---------- |
| drivers/gpu/drm/radeon/radeon_mode.h | 1 |
| 2 files changed, 43 insertions(+), 18 deletions(-) |
| |
| --- a/drivers/gpu/drm/radeon/radeon_cursor.c |
| +++ b/drivers/gpu/drm/radeon/radeon_cursor.c |
| @@ -90,6 +90,9 @@ static void radeon_show_cursor(struct dr |
| struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
| struct radeon_device *rdev = crtc->dev->dev_private; |
| |
| + if (radeon_crtc->cursor_out_of_bounds) |
| + return; |
| + |
| if (ASIC_IS_DCE4(rdev)) { |
| WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, |
| upper_32_bits(radeon_crtc->cursor_addr)); |
| @@ -148,16 +151,17 @@ static int radeon_cursor_move_locked(str |
| x += crtc->x; |
| y += crtc->y; |
| } |
| - DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); |
| |
| - if (x < 0) { |
| + if (x < 0) |
| xorigin = min(-x, radeon_crtc->max_cursor_width - 1); |
| - x = 0; |
| - } |
| - if (y < 0) { |
| + if (y < 0) |
| yorigin = min(-y, radeon_crtc->max_cursor_height - 1); |
| - y = 0; |
| + |
| + if (!ASIC_IS_AVIVO(rdev)) { |
| + x += crtc->x; |
| + y += crtc->y; |
| } |
| + DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); |
| |
| /* fixed on DCE6 and newer */ |
| if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) { |
| @@ -180,27 +184,31 @@ static int radeon_cursor_move_locked(str |
| if (i > 1) { |
| int cursor_end, frame_end; |
| |
| - cursor_end = x - xorigin + w; |
| + cursor_end = x + w; |
| frame_end = crtc->x + crtc->mode.crtc_hdisplay; |
| if (cursor_end >= frame_end) { |
| w = w - (cursor_end - frame_end); |
| if (!(frame_end & 0x7f)) |
| w--; |
| - } else { |
| - if (!(cursor_end & 0x7f)) |
| - w--; |
| + } else if (cursor_end <= 0) { |
| + goto out_of_bounds; |
| + } else if (!(cursor_end & 0x7f)) { |
| + w--; |
| } |
| if (w <= 0) { |
| - w = 1; |
| - cursor_end = x - xorigin + w; |
| - if (!(cursor_end & 0x7f)) { |
| - x--; |
| - WARN_ON_ONCE(x < 0); |
| - } |
| + goto out_of_bounds; |
| } |
| } |
| } |
| |
| + if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) || |
| + x >= (crtc->x + crtc->mode.crtc_hdisplay) || |
| + y >= (crtc->y + crtc->mode.crtc_vdisplay)) |
| + goto out_of_bounds; |
| + |
| + x += xorigin; |
| + y += yorigin; |
| + |
| if (ASIC_IS_DCE4(rdev)) { |
| WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); |
| WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); |
| @@ -212,6 +220,9 @@ static int radeon_cursor_move_locked(str |
| WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, |
| ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); |
| } else { |
| + x -= crtc->x; |
| + y -= crtc->y; |
| + |
| if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) |
| y *= 2; |
| |
| @@ -232,6 +243,19 @@ static int radeon_cursor_move_locked(str |
| radeon_crtc->cursor_x = x; |
| radeon_crtc->cursor_y = y; |
| |
| + if (radeon_crtc->cursor_out_of_bounds) { |
| + radeon_crtc->cursor_out_of_bounds = false; |
| + if (radeon_crtc->cursor_bo) |
| + radeon_show_cursor(crtc); |
| + } |
| + |
| + return 0; |
| + |
| + out_of_bounds: |
| + if (!radeon_crtc->cursor_out_of_bounds) { |
| + radeon_hide_cursor(crtc); |
| + radeon_crtc->cursor_out_of_bounds = true; |
| + } |
| return 0; |
| } |
| |
| @@ -308,12 +332,12 @@ int radeon_crtc_cursor_set2(struct drm_c |
| x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x; |
| y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y; |
| |
| - radeon_cursor_move_locked(crtc, x, y); |
| - |
| radeon_crtc->cursor_width = width; |
| radeon_crtc->cursor_height = height; |
| radeon_crtc->cursor_hot_x = hot_x; |
| radeon_crtc->cursor_hot_y = hot_y; |
| + |
| + radeon_cursor_move_locked(crtc, x, y); |
| } |
| |
| radeon_show_cursor(crtc); |
| --- a/drivers/gpu/drm/radeon/radeon_mode.h |
| +++ b/drivers/gpu/drm/radeon/radeon_mode.h |
| @@ -330,6 +330,7 @@ struct radeon_crtc { |
| u16 lut_r[256], lut_g[256], lut_b[256]; |
| bool enabled; |
| bool can_tile; |
| + bool cursor_out_of_bounds; |
| uint32_t crtc_offset; |
| struct drm_gem_object *cursor_bo; |
| uint64_t cursor_addr; |