[Intel-gfx] [PATCH] drm/i915: HSW GT3 Slices: exec flag to warn kernel that userspace is using predication

Chris Wilson chris at chris-wilson.co.uk
Tue Oct 22 09:47:34 CEST 2013


On Mon, Oct 21, 2013 at 07:00:18PM -0200, Rodrigo Vivi wrote:
>  static int
> +i915_legacy_userspace_busy(struct drm_device *dev,
> +			   struct intel_ring_buffer *ring)

s/i915_legacy_userspace_busy/gt_legacy_userspace_busy/

As that is a bit more distinctive.

> +{
> +	drm_i915_private_t *dev_priv = dev->dev_private;
> +	int ret;
> +
> +	if (!HAS_SLICE_SHUTDOWN(dev) || ring == &dev_priv->ring[BCS])
> +		return -ENODEV;
> +
> +	if (dev_priv->gt_slices.state_default == 1)
> +		return -EBADE;

This needs to be replaced.

if (dev_priv->gt_slices.config == 2)
  return 0;

> +
> +	ret = intel_ring_begin(ring, 3);

The dword count must be even, or else the hardware chokes.
However, since we cannot interrupt this sequence and leave the hw in an
inconsistent state, we need to emit this entire sequence in a single
block.

> +	if (ret)
> +		return ret;
> +	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
> +	intel_ring_emit(ring, HSW_GT_SLICE_INFO);
> +	intel_ring_emit(ring, SLICE_SEL_BOTH);
> +	intel_ring_advance(ring);
> +
> +	ret = intel_ring_begin(ring, 3);
> +	if (ret)
> +		return ret;
> +	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
> +	intel_ring_emit(ring, MI_PREDICATE_RESULT_2);
> +	intel_ring_emit(ring, LOWER_SLICE_ENABLED);
> +	intel_ring_advance(ring);
> +
> +	ret = intel_ring_begin(ring, 3);
> +	if (ret)
> +		return ret;
> +	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
> +	intel_ring_emit(ring, HSW_SLICESHUTDOWN);
> +	intel_ring_emit(ring, ~SLICE_SHUTDOWN);
> +	intel_ring_advance(ring);
> +
> +	ret = intel_ring_begin(ring, 3);
> +	if (ret)
> +		return ret;
> +	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
> +	intel_ring_emit(ring, RC_IDLE_MAX_COUNT);
> +	intel_ring_emit(ring, CS_IDLE_COUNT_1US);
> +	intel_ring_advance(ring);
> +	ret = intel_ring_begin(ring, 3);
> +	if (ret)
> +		return ret;
> +	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
> +	intel_ring_emit(ring, WAIT_FOR_RC6_EXIT);
> +	intel_ring_emit(ring, WAIT_RC6_EXIT | MASK_WAIT_RC6_EXIT);

_MASKED_BIT_ENABLE(WAIT_RC6_EXIT)

> +	intel_ring_advance(ring);
> +
> +	ret = intel_ring_begin(ring, 3);
> +	if (ret)
> +		return ret;
> +	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
> +	intel_ring_emit(ring, RC_IDLE_MAX_COUNT);
> +	intel_ring_emit(ring, CS_IDLE_COUNT_5US);
> +	intel_ring_advance(ring);
> +
    dev_priv->gt_slices.config = 2;
> +	return 0;
> +}
> +
> +static int
>  i915_gem_do_execbuffer(struct drm_device *dev, void *data,
>  		       struct drm_file *file,
>  		       struct drm_i915_gem_execbuffer2 *args,
> @@ -999,6 +1063,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
>  		return -EINVAL;
>  	}
>  
> +	if ((args->flags & I915_EXEC_USE_PREDICATE) == 0 &&
> +	    !dev_priv->gt_slices.legacy_userspace_busy)
> +		if (i915_legacy_userspace_busy(dev, ring) == 0)
> +			dev_priv->gt_slices.legacy_userspace_busy = true;

Now here we cannot just ignore a failure to switch slice configuration.

 static bool gt_legacy_userspace(struct intel_ring_buffer *ring,
  		                 struct drm_i915_gem_execbuffer2 *args)
 {
    if (ring->id == BCS)
       return false;

    if (!HAS_SLICE_SHUTDOWN(ring->dev))
       return false;

    return (args->flags & I915_EXEC_USE_PREDICATE) == 0;
 }

 if (gt_legacy_userspace(ring, args)) {
    ret = gt_legacy_userspace_busy(ring);
    if (ret)
       return ret;

    dev_priv->gt_slices.legacy_userspace_busy = true;
 }


> +
>  	mode = args->flags & I915_EXEC_CONSTANTS_MASK;
>  	mask = I915_EXEC_CONSTANTS_MASK;
>  	switch (mode) {
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 497c441..0146bef 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -277,6 +277,17 @@
>  #define   SLICE_STATUS_MAIN_ON	(2<<0)
>  #define   SLICE_STATUS_BOTH_ON	(3<<0)
>  
> +#define HSW_SLICESHUTDOWN	0xA190
> +#define   SLICE_SHUTDOWN	(1<<0)
> +
> +#define RC_IDLE_MAX_COUNT	0x2054
> +#define   CS_IDLE_COUNT_1US	(1<<1)
> +#define   CS_IDLE_COUNT_5US	(1<<3)
> +
> +#define WAIT_FOR_RC6_EXIT	0x20CC
> +#define   WAIT_RC6_EXIT		(1<<0)
> +#define   MASK_WAIT_RC6_EXIT	(1<<16)
> +
>  /*
>   * 3D instructions used by the kernel
>   */
> diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
> index 86ccd52..1dd57fb 100644
> --- a/drivers/gpu/drm/i915/i915_sysfs.c
> +++ b/drivers/gpu/drm/i915/i915_sysfs.c
> @@ -125,8 +125,7 @@ static ssize_t gt_slice_config_show(struct device *kdev,
>  	struct drm_device *dev = minor->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  
> -	return sprintf(buf, "%s\n", I915_READ(MI_PREDICATE_RESULT_2) ==
> -		       LOWER_SLICE_ENABLED ? "full" : "half");
> +	return sprintf(buf, "%s\n", I915_READ(MI_PREDICATE_RESULT_2) == LOWER_SLICE_ENABLED ? "full" : "half");
>  }
>  
>  static ssize_t gt_slice_config_store(struct device *kdev,
> @@ -135,16 +134,19 @@ static ssize_t gt_slice_config_store(struct device *kdev,
>  {
>  	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
>  	struct drm_device *dev = minor->dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
>  	int ret;

This cannot change state whilst legacy_userspace_busy.
>  
>  	if (!strncmp(buf, "full", sizeof("full") - 1)) {
>  		ret = intel_set_gt_full(dev);
>  		if (ret)
>  			return ret;
> +		dev_priv->gt_slices.state_default = 1;
dev_priv->gt_slices.max_config = 2;
>  	} else if (!strncmp(buf, "half", sizeof("half") - 1)) {
>  		ret = intel_set_gt_half(dev);
>  		if (ret)
>  			return ret;
> +		dev_priv->gt_slices.state_default = 0;
dev_priv->gt_slices.max_config = 1;
>  	} else
>  		return -EINVAL;

(void)intel_gt_update_slice_config(dev);

where

  int intel_gt_update_slice_config(struct drm_device *dev)
  {
     int config;

     if (!HAS_SLICE_SHUTDOWN(dev))
       return -ENODEV;

     if (dev_priv-gt_slices.legacy_userspace_busy)
       return -EBUSY;
       
     config = min(dev_priv->gt_slices.config,
                  dev_priv->gt_slices.max_config);
     if (config == dev_priv->gt_slices.config)
       return 0;

     /* slice_set_config(dev, config); ? */
     switch (config) {
     case 1: gt_slice_set_half(dev); break;
     case 2: gt_slice_set_full(dev); break;
     default: return -EINVAL;
     }

     dev_priv->gt_slices.config = config;
     return 0;
  }

>  	return count;
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 4f1b636..3810ecf 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -7778,6 +7778,12 @@ void intel_mark_idle(struct drm_device *dev)
>  
>  	if (dev_priv->info->gen >= 6)
>  		gen6_rps_idle(dev->dev_private);
> +
> +	if (HAS_SLICE_SHUTDOWN(dev) &&
> +	    dev_priv->gt_slices.legacy_userspace_busy) {
> +		intel_set_gt_half_async(dev);
> +	}

Just if (dev_priv->gt_slices.legacy_userspace_busy) {
         dev_priv->gt_slices.legacy_userspace_busy = false;
         intel_gt_update_slice_config(dev);
     }

-- 
Chris Wilson, Intel Open Source Technology Centre



More information about the Intel-gfx mailing list