Commit d549a370 authored by Michel Dänzer's avatar Michel Dänzer Committed by Ben Hutchings

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

commit 6b16cf77 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=1000433Signed-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>
[bwh: Backported to 3.16:
 - Drop changes to radeon_crtc_cursor_set2()
 - Adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 2e08ab8a
...@@ -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(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset); WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN | WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
...@@ -228,16 +231,17 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, ...@@ -228,16 +231,17 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
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)) {
...@@ -260,27 +264,31 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, ...@@ -260,27 +264,31 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
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;
radeon_lock_cursor(crtc, true); radeon_lock_cursor(crtc, true);
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);
...@@ -293,6 +301,9 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, ...@@ -293,6 +301,9 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
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;
...@@ -310,5 +321,18 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, ...@@ -310,5 +321,18 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
} }
radeon_lock_cursor(crtc, false); radeon_lock_cursor(crtc, false);
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;
} }
...@@ -318,6 +318,7 @@ struct radeon_crtc { ...@@ -318,6 +318,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