[Intel-gfx] [PATCH] drm/i915: Unset cursor if out-of-bounds upon mode change (v4)

Christopher James Halse Rogers christopher.halse.rogers at canonical.com
Fri Jul 9 12:23:09 CEST 2010


On Fri, 2010-07-09 at 08:45 +0100, Chris Wilson wrote:
> The docs warn that to position the cursor such that no part of it is
> visible on the pipe is an undefined operation. Avoid such circumstances
> upon changing the mode, or at any other time, by unsetting the cursor if
> it moves out of bounds.
> 
> "For normal high resolution display modes, the cursor must have at least a
> single pixel positioned over the active screen.” (p143, p148 of the hardware
> registers docs).
> 
> Fixes:
> 
>   Bug 24748 - [965G] Graphics crashes when resolution is changed with KMS
>               enabled
>   https://bugs.freedesktop.org/show_bug.cgi?id=24748
> 
> v2: Only update the cursor registers if they change.
> v3: Fix the unsigned comparision of x,y against width,height.
> v4: Always set CUR.BASE or else the cursor may become corrupt.
> 
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> Reported-by: Christian Eggers <ceggers at gmx.de>
> Cc: Christopher James Halse Rogers  <chalserogers at gmail.com>
> Cc: stable at kernel.org
> ---
>  drivers/gpu/drm/i915/intel_display.c |  144 ++++++++++++++++++++++------------
>  drivers/gpu/drm/i915/intel_drv.h     |    8 ++-
>  2 files changed, 99 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 1f06f3f..5f51084 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -42,6 +42,7 @@
>  bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
>  static void intel_update_watermarks(struct drm_device *dev);
>  static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
> +static void intel_crtc_update_cursor(struct drm_crtc *crtc);
>  
>  typedef struct {
>      /* given values */
> @@ -3532,6 +3533,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
>  		return -EINVAL;
>  	}
>  
> +	/* Ensure that the cursor is valid for the new mode before changing... */
> +	intel_crtc_update_cursor(crtc);
> +
>  	if (is_lvds && dev_priv->lvds_downclock_avail) {
>  		has_reduced_clock = limit->find_pll(limit, crtc,
>  							    dev_priv->lvds_downclock,
> @@ -4069,6 +4073,85 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
>  	}
>  }
>  
> +/* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
> +static void intel_crtc_update_cursor(struct drm_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +	int pipe = intel_crtc->pipe;
> +	int x = intel_crtc->cursor_x;
> +	int y = intel_crtc->cursor_y;
> +	uint32_t base, pos;
> +	bool visible;
> +
> +	pos = 0;
> +
> +	if (crtc->fb) {
> +		base = intel_crtc->cursor_addr;
> +		if (x > (int) crtc->fb->width)
> +			base = 0;
> +
> +		if (y > (int) crtc->fb->height)
> +			base = 0;
> +	} else
> +		base = 0;
> +
> +	if (x < 0) {
> +		if (x + intel_crtc->cursor_width < 0)
> +			base = 0;
> +
> +		pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
> +		x = -x;
> +	}
> +	pos |= x << CURSOR_X_SHIFT;
> +
> +	if (y < 0) {
> +		if (y + intel_crtc->cursor_height < 0)
> +			base = 0;
> +
> +		pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
> +		y = -y;
> +	}
> +	pos |= y << CURSOR_Y_SHIFT;
> +
> +	visible = base != 0;
> +	if (!visible && !intel_crtc->cursor_visble)
> +		return;
> +
> +	I915_WRITE(pipe == 0 ? CURAPOS : CURBPOS, pos);
> +	if (intel_crtc->cursor_visble != visible) {
> +		uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR);
> +		if (base) {
> +			/* Hooray for CUR*CNTR differences */
> +			if (IS_MOBILE(dev) || IS_I9XX(dev)) {
> +				cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
> +				cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
> +				cntl |= pipe << 28; /* Connect to correct pipe */
> +			} else {
> +				cntl &= ~(CURSOR_FORMAT_MASK);
> +				cntl |= CURSOR_ENABLE;
> +				cntl |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
> +			}
> +		} else {
> +			if (IS_MOBILE(dev) || IS_I9XX(dev)) {
> +				cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
> +				cntl |= CURSOR_MODE_DISABLE;
> +			} else {
> +				cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
> +			}
> +		}
> +		I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl);
> +
> +		intel_crtc->cursor_visble = visible;
> +	}
> +	/* and commit changes on next vblank */
> +	I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base);
> +
> +	if (visible)
> +		intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj);
> +}
> +
>  static int intel_crtc_cursor_set(struct drm_crtc *crtc,
>  				 struct drm_file *file_priv,
>  				 uint32_t handle,
> @@ -4079,11 +4162,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	struct drm_gem_object *bo;
>  	struct drm_i915_gem_object *obj_priv;
> -	int pipe = intel_crtc->pipe;
> -	uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
> -	uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
> -	uint32_t temp = I915_READ(control);
> -	size_t addr;
> +	uint32_t addr;
>  	int ret;
>  
>  	DRM_DEBUG_KMS("\n");
> @@ -4091,12 +4170,6 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
>  	/* if we want to turn off the cursor ignore width and height */
>  	if (!handle) {
>  		DRM_DEBUG_KMS("cursor off\n");
> -		if (IS_MOBILE(dev) || IS_I9XX(dev)) {
> -			temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
> -			temp |= CURSOR_MODE_DISABLE;
> -		} else {
> -			temp &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
> -		}
>  		addr = 0;
>  		bo = NULL;
>  		mutex_lock(&dev->struct_mutex);
> @@ -4138,7 +4211,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
>  
>  		addr = obj_priv->gtt_offset;
>  	} else {
> -		ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
> +		ret = i915_gem_attach_phys_object(dev, bo,
> +						  (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
>  		if (ret) {
>  			DRM_ERROR("failed to attach phys object\n");
>  			goto fail_locked;
> @@ -4149,21 +4223,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
>  	if (!IS_I9XX(dev))
>  		I915_WRITE(CURSIZE, (height << 12) | width);
>  
> -	/* Hooray for CUR*CNTR differences */
> -	if (IS_MOBILE(dev) || IS_I9XX(dev)) {
> -		temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
> -		temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
> -		temp |= (pipe << 28); /* Connect to correct pipe */
> -	} else {
> -		temp &= ~(CURSOR_FORMAT_MASK);
> -		temp |= CURSOR_ENABLE;
> -		temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
> -	}
> -
>   finish:
> -	I915_WRITE(control, temp);
> -	I915_WRITE(base, addr);
> -
>  	if (intel_crtc->cursor_bo) {
>  		if (dev_priv->info->cursor_needs_physical) {
>  			if (intel_crtc->cursor_bo != bo)
> @@ -4177,6 +4237,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
>  
>  	intel_crtc->cursor_addr = addr;
>  	intel_crtc->cursor_bo = bo;
> +	intel_crtc->cursor_width = width;
> +	intel_crtc->cursor_height = height;
> +
> +	intel_crtc_update_cursor(crtc);
>  
>  	return 0;
>  fail_unpin:
> @@ -4190,34 +4254,12 @@ fail:
>  
>  static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
>  {
> -	struct drm_device *dev = crtc->dev;
> -	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	struct intel_framebuffer *intel_fb;
> -	int pipe = intel_crtc->pipe;
> -	uint32_t temp = 0;
> -	uint32_t adder;
> -
> -	if (crtc->fb) {
> -		intel_fb = to_intel_framebuffer(crtc->fb);
> -		intel_mark_busy(dev, intel_fb->obj);
> -	}
> -
> -	if (x < 0) {
> -		temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
> -		x = -x;
> -	}
> -	if (y < 0) {
> -		temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
> -		y = -y;
> -	}
>  
> -	temp |= x << CURSOR_X_SHIFT;
> -	temp |= y << CURSOR_Y_SHIFT;
> +	intel_crtc->cursor_x = x;
> +	intel_crtc->cursor_y = y;
>  
> -	adder = intel_crtc->cursor_addr;
> -	I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
> -	I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder);
> +	intel_crtc_update_cursor(crtc);
>  
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 437233d..e3cad5c 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -142,8 +142,6 @@ struct intel_crtc {
>  	struct drm_crtc base;
>  	enum pipe pipe;
>  	enum plane plane;
> -	struct drm_gem_object *cursor_bo;
> -	uint32_t cursor_addr;
>  	u8 lut_r[256], lut_g[256], lut_b[256];
>  	int dpms_mode;
>  	bool busy; /* is scanout buffer being updated frequently? */
> @@ -152,6 +150,12 @@ struct intel_crtc {
>  	struct intel_overlay *overlay;
>  	struct intel_unpin_work *unpin_work;
>  	int fdi_lanes;
> +
> +	struct drm_gem_object *cursor_bo;
> +	uint32_t cursor_addr;
> +	int16_t cursor_x, cursor_y;
> +	int16_t cursor_width, cursor_height;
> +	bool cursor_visble;
>  };
>  
>  #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)

Tested on my Q965 and GM45.  Fixes the reported bug, hasn't introduced
any visible regressions.

This matches my reading of the hardware docs, too.

Tested-by: Christopher James Halse Rogers
<christopher.halse.rogers at canonical.com>
Reviewed-by: Christopher James Halse Rogers
<christopher.halse.rogers at canonical.com>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: This is a digitally signed message part
URL: <http://lists.freedesktop.org/archives/intel-gfx/attachments/20100709/be92c0c7/attachment.sig>


More information about the Intel-gfx mailing list