summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMika Kuoppala <mika.kuoppala@linux.intel.com>2019-02-27 16:48:36 +0200
committerMika Kuoppala <mika.kuoppala@linux.intel.com>2019-02-27 18:47:36 +0200
commit0f811749e77dff7ea2c48bdd18fe7df30cdffa4a (patch)
tree1ccae411880ebfc1f29b909a427b6fbd5fb3820f
parenta6679deb0048bfb900d7926b851527055f7a403c (diff)
drm/i915: Disable PSMI idle messaging when stopping ringring_stop
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>
-rw-r--r--drivers/gpu/drm/i915/intel_engine_cs.c56
1 files changed, 55 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index ad437a6927dc..0e2ed77e4357 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -725,7 +725,7 @@ err_unpin_kernel:
/**
* 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",