[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