mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: 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>
This commit is contained in:
		
							parent
							
								
									4349bd775c
								
							
						
					
					
						commit
						6b16cf7785
					
				
					 2 changed files with 43 additions and 18 deletions
				
			
		| 
						 | 
					@ -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)
 | 
				
			||||||
		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)
 | 
				
			||||||
		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)
 | 
				
			||||||
		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)
 | 
				
			||||||
		       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,
 | 
				
			||||||
		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 {
 | 
				
			||||||
	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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue