diff options
author | Mika Kuoppala <mika.kuoppala@linux.intel.com> | 2019-02-27 16:48:36 +0200 |
---|---|---|
committer | Mika Kuoppala <mika.kuoppala@linux.intel.com> | 2019-02-27 18:47:36 +0200 |
commit | 0f811749e77dff7ea2c48bdd18fe7df30cdffa4a (patch) | |
tree | 1ccae411880ebfc1f29b909a427b6fbd5fb3820f | |
parent | a6679deb0048bfb900d7926b851527055f7a403c (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.c | 56 |
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", |