Skip to content

Commit

Permalink
drm/radeon: Hide the HW cursor while it's out of bounds
Browse files Browse the repository at this point in the history
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: [email protected]
Signed-off-by: Michel Dänzer <[email protected]>
Reviewed-by: Alex Deucher <[email protected]> (v1)
Signed-off-by: Alex Deucher <[email protected]>
  • Loading branch information
Michel Dänzer authored and alexdeucher committed Dec 6, 2016
1 parent 4349bd7 commit 6b16cf7
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 18 deletions.
60 changes: 42 additions & 18 deletions drivers/gpu/drm/radeon/radeon_cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ static void radeon_show_cursor(struct drm_crtc *crtc)
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));
Expand Down Expand Up @@ -151,16 +154,17 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
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)) {
Expand All @@ -183,27 +187,31 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
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);
Expand All @@ -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,
((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;

Expand All @@ -232,6 +243,19 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
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;
}

Expand Down Expand Up @@ -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;
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);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/radeon/radeon_mode.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 6b16cf7

Please sign in to comment.