Commit 6b16cf77 authored by Michel Dänzer's avatar Michel Dänzer Committed by Alex Deucher

drm/radeon: Hide the HW cursor while it's out of bounds

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
Cc: stable@vger.kernel.org
Signed-off-by: default avatarMichel Dänzer <michel.daenzer@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com> (v1)
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 4349bd77
...@@ -90,6 +90,9 @@ static void radeon_show_cursor(struct drm_crtc *crtc) ...@@ -90,6 +90,9 @@ static void radeon_show_cursor(struct drm_crtc *crtc)
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct radeon_device *rdev = crtc->dev->dev_private; struct radeon_device *rdev = crtc->dev->dev_private;
if (radeon_crtc->cursor_out_of_bounds)
return;
if (ASIC_IS_DCE4(rdev)) { if (ASIC_IS_DCE4(rdev)) {
WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
upper_32_bits(radeon_crtc->cursor_addr)); upper_32_bits(radeon_crtc->cursor_addr));
...@@ -151,16 +154,17 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) ...@@ -151,16 +154,17 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
x += crtc->x; x += crtc->x;
y += crtc->y; 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); 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); 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 */ /* fixed on DCE6 and newer */
if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) { if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
...@@ -183,27 +187,31 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) ...@@ -183,27 +187,31 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
if (i > 1) { if (i > 1) {
int cursor_end, frame_end; int cursor_end, frame_end;
cursor_end = x - xorigin + w; cursor_end = x + w;
frame_end = crtc->x + crtc->mode.crtc_hdisplay; frame_end = crtc->x + crtc->mode.crtc_hdisplay;
if (cursor_end >= frame_end) { if (cursor_end >= frame_end) {
w = w - (cursor_end - frame_end); w = w - (cursor_end - frame_end);
if (!(frame_end & 0x7f)) if (!(frame_end & 0x7f))
w--; w--;
} else { } else if (cursor_end <= 0) {
if (!(cursor_end & 0x7f)) goto out_of_bounds;
w--; } else if (!(cursor_end & 0x7f)) {
w--;
} }
if (w <= 0) { if (w <= 0) {
w = 1; goto out_of_bounds;
cursor_end = x - xorigin + w;
if (!(cursor_end & 0x7f)) {
x--;
WARN_ON_ONCE(x < 0);
}
} }
} }
} }
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)) { if (ASIC_IS_DCE4(rdev)) {
WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
...@@ -215,6 +223,9 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) ...@@ -215,6 +223,9 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
} else { } else {
x -= crtc->x;
y -= crtc->y;
if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
y *= 2; y *= 2;
...@@ -232,6 +243,19 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) ...@@ -232,6 +243,19 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
yorigin * 256); yorigin * 256);
} }
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; return 0;
} }
...@@ -308,12 +332,12 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc, ...@@ -308,12 +332,12 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x; x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y; 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_width = width;
radeon_crtc->cursor_height = height; radeon_crtc->cursor_height = height;
radeon_crtc->cursor_hot_x = hot_x; radeon_crtc->cursor_hot_x = hot_x;
radeon_crtc->cursor_hot_y = hot_y; radeon_crtc->cursor_hot_y = hot_y;
radeon_cursor_move_locked(crtc, x, y);
} }
radeon_show_cursor(crtc); radeon_show_cursor(crtc);
......
...@@ -330,6 +330,7 @@ struct radeon_crtc { ...@@ -330,6 +330,7 @@ struct radeon_crtc {
u16 lut_r[256], lut_g[256], lut_b[256]; u16 lut_r[256], lut_g[256], lut_b[256];
bool enabled; bool enabled;
bool can_tile; bool can_tile;
bool cursor_out_of_bounds;
uint32_t crtc_offset; uint32_t crtc_offset;
struct drm_gem_object *cursor_bo; struct drm_gem_object *cursor_bo;
uint64_t cursor_addr; uint64_t cursor_addr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment