[Intel-gfx] [RFC v2] drm/i915/chv: Clip cursor for CHV pipe C HW Cursor pos < 0

Shobhit Kumar shobhit.kumar at intel.com
Wed Jun 29 13:02:48 UTC 2016


On 06/29/2016 06:24 PM, Shobhit Kumar wrote:
> From: Shobhit Kumar <shobhit.kumar at intel.com>
>
> CHV pipe C hits underrun when we get negative crtc_x values of cursor.
> To avoid this we clip and shift the cursor image by negative crtc_x
> value.
>
> v2: Make a copy of cursor plane state and allocate new gem object and fb
>     for clipped cursor and use that in case of negative cursor position
>
> v3: Updated error handling
>     Pin the gem object before use.

I tested a modified version of this on 3.18 kernel on ChromeOS. Does 
work fine, but few WARN dumps from might_sleep() in atomic context while 
allocating cursor gem bo. I can allocate it one time during plane 
creation but how do I know the size of incoming bo ? If I allocate for 
say large cursor 256x256, ioremap_wc also has same WARN dumps. Need to 
remap in update function. Any hints how to go about it ? Maybe I should 
do this hack in check_plane rather than update plane ?

Regards
Shobhit

>
> Signed-off-by: Akshu Agrawal <akshu.agrawal at intel.com>
> Signed-off-by: Shobhit Kumar <shobhit.kumar at intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h      |   7 ++
>  drivers/gpu/drm/i915/intel_display.c | 131 ++++++++++++++++++++++++++++++++++-
>  2 files changed, 137 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 724d34b..1e59c02 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2041,6 +2041,13 @@ struct drm_i915_private {
>  	struct intel_encoder *dig_port_map[I915_MAX_PORTS];
>
>  	/*
> +	* Temporary copy of cursor plane state for CHV PIPE_C
> +	* Will be initialized only when crtc_x < 0 as there is a
> +	* HW bug causing pipe underrun
> +	*/
> +	struct intel_plane_state *cursor_state;
> +
> +	/*
>  	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
>  	 * will be rejected. Instead look for a better place.
>  	 */
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index c3b5dc8..e6c103a 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -14456,6 +14456,132 @@ intel_update_cursor_plane(struct drm_plane *plane,
>  	intel_crtc_update_cursor(crtc, state);
>  }
>
> +static void
> +intel_update_chv_pipe_c_cursor_plane(struct drm_plane *plane,
> +		const struct intel_crtc_state *crtc_state,
> +		const struct intel_plane_state *state)
> +{
> +	struct drm_crtc *crtc = crtc_state->base.crtc;
> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +	struct drm_device *dev = plane->dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
> +	struct drm_i915_gem_object *cur_obj = NULL, *use_obj = NULL;
> +	uint32_t addr;
> +	struct intel_plane_state *cursor_state = dev_priv->cursor_state;
> +	const struct intel_plane_state *use_state;
> +	char __iomem *src, *dst;
> +	bool pinned = true;
> +
> +	if (state->visible && state->base.crtc_x < 0) {
> +		int bytes_per_pixel = state->base.fb->bits_per_pixel / 8;
> +		int x = state->base.crtc_x;
> +		int width = state->base.crtc_w;
> +		int height = state->base.crtc_h;
> +		struct drm_mode_fb_cmd2 mode_cmd = { 0 };
> +		int i;
> +
> +		if (!cursor_state) {
> +			cursor_state = kzalloc(sizeof(*cursor_state), GFP_KERNEL);
> +			if (!cursor_state) {
> +				use_state = state;
> +				use_obj = obj;
> +				goto update;
> +			}
> +
> +			memcpy(cursor_state, state, sizeof(*state));
> +
> +			/* Allocate new gem object */
> +			cur_obj = i915_gem_object_create(dev, obj->base.size);
> +			if (IS_ERR(cur_obj))
> +				goto gem_err;
> +
> +			mode_cmd.width = cursor_state->base.fb->width;
> +			mode_cmd.height = cursor_state->base.fb->height;
> +			mode_cmd.pitches[0] = cursor_state->base.fb->pitches[0];
> +			mode_cmd.pixel_format = cursor_state->base.fb->pixel_format;
> +
> +			cursor_state->base.fb = intel_framebuffer_create(dev, &mode_cmd, cur_obj);
> +			if (IS_ERR(cursor_state->base.fb)) {
> +				drm_gem_object_unreference_unlocked(&cur_obj->base);
> +				goto gem_err;
> +			}
> +
> +			if (i915_gem_obj_ggtt_pin(cur_obj, 0, 0) < 0) {
> +				drm_gem_object_unreference_unlocked(&cur_obj->base);
> +				pinned = false;
> +				goto cleanup;
> +			}
> +
> +			dev_priv->cursor_state = cursor_state;
> +		} else
> +			cur_obj = intel_fb_obj(cursor_state->base.fb);
> +
> +		src = ioremap_wc(dev_priv->ggtt.mappable_base +
> +				i915_gem_obj_ggtt_offset(obj),
> +				obj->base.size);
> +
> +		dst = ioremap_wc(dev_priv->ggtt.mappable_base +
> +				i915_gem_obj_ggtt_offset(cur_obj),
> +				cur_obj->base.size);
> +
> +		/* shift the original cusrsor in to copy buffer offsetting -ive pos */
> +		x = -x;
> +		for (i = 0; i < height; i++) {
> +			src += x * bytes_per_pixel;
> +			memcpy(dst, src, (width - x) * bytes_per_pixel);
> +			dst += (width - x) * bytes_per_pixel;
> +			memset(dst, 0, x * bytes_per_pixel);
> +			dst += x * bytes_per_pixel;
> +			src += (width -x) * bytes_per_pixel;
> +		}
> +
> +		iounmap(src);
> +		iounmap(dst);
> +
> +		cursor_state->base.crtc_x = 0;
> +		use_obj = cur_obj;
> +		use_state = cursor_state;
> +
> +		goto update;
> +	}
> +
> +cleanup:
> +	if (cursor_state) {
> +		struct intel_framebuffer *intel_fb = to_intel_framebuffer(cursor_state->base.fb);
> +
> +		if (pinned)
> +			i915_gem_object_ggtt_unpin(cur_obj);
> +
> +		drm_framebuffer_cleanup(cursor_state->base.fb);
> +		mutex_lock(&dev->struct_mutex);
> +		drm_gem_object_unreference(&intel_fb->obj->base);
> +		mutex_unlock(&dev->struct_mutex);
> +		kfree(intel_fb);
> +	}
> +
> +gem_err:
> +	if (dev_priv->cursor_state) {
> +		kfree(dev_priv->cursor_state);
> +		dev_priv->cursor_state = NULL;
> +	}
> +
> +	use_state = state;
> +	use_obj = obj;
> +
> +update:
> +	if (!use_obj)
> +		addr = 0;
> +	else if (!INTEL_INFO(dev)->cursor_needs_physical)
> +		addr = i915_gem_obj_ggtt_offset(use_obj);
> +	else
> +		addr = use_obj->phys_handle->busaddr;
> +
> +	intel_crtc->cursor_addr = addr;
> +
> +	intel_crtc_update_cursor(crtc, use_state);
> +}
> +
>  static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
>  						   int pipe)
>  {
> @@ -14478,7 +14604,10 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
>  	cursor->plane = pipe;
>  	cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe);
>  	cursor->check_plane = intel_check_cursor_plane;
> -	cursor->update_plane = intel_update_cursor_plane;
> +	if (IS_CHERRYVIEW(dev) && pipe == PIPE_C)
> +		cursor->update_plane = intel_update_chv_pipe_c_cursor_plane;
> +	else
> +		cursor->update_plane = intel_update_cursor_plane;
>  	cursor->disable_plane = intel_disable_cursor_plane;
>
>  	ret = drm_universal_plane_init(dev, &cursor->base, 0,
>


More information about the Intel-gfx mailing list