diff mbox series

[3/3] drm/i915: Disable PSMI idle messaging when stopping ring

Message ID 20190227165850.17277-3-mika.kuoppala@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series None | expand

Commit Message

Mika Kuoppala Feb. 27, 2019, 4:58 p.m. UTC
Hardware cannot be in a middle of idle flow messaging
when we pull the plug from ringbuffer. Disable idle
messaging before we do so to avoid potential deadlock
on engine initialization and reset.

v2: INVALID_MMIO_REG, unconditional enable (Chris)

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_engine_cs.c | 56 +++++++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

Comments

Chris Wilson Feb. 27, 2019, 5:14 p.m. UTC | #1
Quoting Mika Kuoppala (2019-02-27 16:58:50)
> Hardware cannot be in a middle of idle flow messaging
> when we pull the plug from ringbuffer. Disable idle
> messaging before we do so to avoid potential deadlock
> on engine initialization and reset.
> 
> v2: INVALID_MMIO_REG, unconditional enable (Chris)
> 
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_engine_cs.c | 56 +++++++++++++++++++++++++-
>  1 file changed, 55 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
> index a8e47cfa6e35..fe7fca392b63 100644
> --- a/drivers/gpu/drm/i915/intel_engine_cs.c
> +++ b/drivers/gpu/drm/i915/intel_engine_cs.c
> @@ -725,7 +725,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
>  
>  /**
>   * intel_engines_cleanup_common - cleans up the engine state created by
> - *                                the common initiailizers.
> + *                                the common initializers.
>   * @engine: Engine to cleanup.
>   *
>   * This cleans up everything created by the common helpers.
> @@ -826,6 +826,55 @@ void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine)
>                       _MASKED_BIT_DISABLE(STOP_RING));
>  }
>  
> +static i915_reg_t get_idle_poll_reg(const struct intel_engine_cs *engine)
> +{
> +       if (engine->id != RCS)
> +               return INVALID_MMIO_REG;
> +
> +       if (IS_GEN(engine->i915, 9))
> +               return GEN9_RCS_FE_FSM2;
> +
> +       if (IS_GEN(engine->i915, 8))
> +               return GEN6_RCS_PWR_FSM;
> +
> +       return INVALID_MMIO_REG;
> +}
> +
> +static void disable_idle_messaging(struct intel_engine_cs *engine)
> +{
> +       struct drm_i915_private *dev_priv = engine->i915;
> +       i915_reg_t poll_reg;
> +
> +       poll_reg = get_idle_poll_reg(engine);
> +       if (!i915_mmio_reg_valid(poll_reg))
> +               return;
> +
> +       GEM_DEBUG_WARN_ON(I915_READ_FW(GEN6_RC_SLEEP_PSMI_CONTROL) &
> +                         GEN6_PSMI_SLEEP_MSG_DISABLE);
> +
> +       I915_WRITE_FW(GEN6_RC_SLEEP_PSMI_CONTROL,
> +                     _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
> +

Needs some reference at least. Or a synposis of what exactly we are
waiting for in a comment.

> +       if (__intel_wait_for_register_fw(dev_priv, poll_reg,
> +                                        0x7f, 0x30,
> +                                        5000, 0,
> +                                        NULL))
> +               DRM_DEBUG_DRIVER("psmi idle msg poll timeout\n");
> +}
> +
> +static void enable_idle_messaging(struct intel_engine_cs *engine)
> +{
> +       struct drm_i915_private *dev_priv = engine->i915;
> +       i915_reg_t poll_reg;
> +
> +       poll_reg = get_idle_poll_reg(engine);
> +       if (!i915_mmio_reg_valid(poll_reg))
> +               return;
> +
> +       I915_WRITE_FW(GEN6_RC_SLEEP_PSMI_CONTROL,
> +                     _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
> +}
> +
>  int intel_engine_stop_ringbuffer(struct intel_engine_cs *engine)
>  {
>         struct drm_i915_private *dev_priv = engine->i915;
> @@ -841,9 +890,14 @@ int intel_engine_stop_ringbuffer(struct intel_engine_cs *engine)
>         I915_WRITE_FW(RING_TAIL(base), 0);
>         POSTING_READ_FW(RING_TAIL(base));
>  
> +       /* Idle messaging needs to be off during ring disable */
> +       disable_idle_messaging(engine);
> +
>         /* The ring must be empty before it is disabled */
>         I915_WRITE_FW(RING_CTL(base), 0);
>  
> +       enable_idle_messaging(engine);
> +
>         /* Check acts as a post */
>         if (I915_READ_FW(RING_HEAD(base))) {
>                 GEM_TRACE("%s: ring head [%x] not parked\n",

Given the history SLEEP_MSG_DISABLE around RING_CTL is not surprising.

Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
-Chris
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index a8e47cfa6e35..fe7fca392b63 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -725,7 +725,7 @@  int intel_engine_init_common(struct intel_engine_cs *engine)
 
 /**
  * intel_engines_cleanup_common - cleans up the engine state created by
- *                                the common initiailizers.
+ *                                the common initializers.
  * @engine: Engine to cleanup.
  *
  * This cleans up everything created by the common helpers.
@@ -826,6 +826,55 @@  void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine)
 		      _MASKED_BIT_DISABLE(STOP_RING));
 }
 
+static i915_reg_t get_idle_poll_reg(const struct intel_engine_cs *engine)
+{
+	if (engine->id != RCS)
+		return INVALID_MMIO_REG;
+
+	if (IS_GEN(engine->i915, 9))
+		return GEN9_RCS_FE_FSM2;
+
+	if (IS_GEN(engine->i915, 8))
+		return GEN6_RCS_PWR_FSM;
+
+	return INVALID_MMIO_REG;
+}
+
+static void disable_idle_messaging(struct intel_engine_cs *engine)
+{
+	struct drm_i915_private *dev_priv = engine->i915;
+	i915_reg_t poll_reg;
+
+	poll_reg = get_idle_poll_reg(engine);
+	if (!i915_mmio_reg_valid(poll_reg))
+		return;
+
+	GEM_DEBUG_WARN_ON(I915_READ_FW(GEN6_RC_SLEEP_PSMI_CONTROL) &
+			  GEN6_PSMI_SLEEP_MSG_DISABLE);
+
+	I915_WRITE_FW(GEN6_RC_SLEEP_PSMI_CONTROL,
+		      _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
+
+	if (__intel_wait_for_register_fw(dev_priv, poll_reg,
+					 0x7f, 0x30,
+					 5000, 0,
+					 NULL))
+		DRM_DEBUG_DRIVER("psmi idle msg poll timeout\n");
+}
+
+static void enable_idle_messaging(struct intel_engine_cs *engine)
+{
+	struct drm_i915_private *dev_priv = engine->i915;
+	i915_reg_t poll_reg;
+
+	poll_reg = get_idle_poll_reg(engine);
+	if (!i915_mmio_reg_valid(poll_reg))
+		return;
+
+	I915_WRITE_FW(GEN6_RC_SLEEP_PSMI_CONTROL,
+		      _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
+}
+
 int intel_engine_stop_ringbuffer(struct intel_engine_cs *engine)
 {
 	struct drm_i915_private *dev_priv = engine->i915;
@@ -841,9 +890,14 @@  int intel_engine_stop_ringbuffer(struct intel_engine_cs *engine)
 	I915_WRITE_FW(RING_TAIL(base), 0);
 	POSTING_READ_FW(RING_TAIL(base));
 
+	/* Idle messaging needs to be off during ring disable */
+	disable_idle_messaging(engine);
+
 	/* The ring must be empty before it is disabled */
 	I915_WRITE_FW(RING_CTL(base), 0);
 
+	enable_idle_messaging(engine);
+
 	/* Check acts as a post */
 	if (I915_READ_FW(RING_HEAD(base))) {
 		GEM_TRACE("%s: ring head [%x] not parked\n",