]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/i915/gen8+: Add RC6 CTX corruption WA
authorImre Deak <imre.deak@intel.com>
Mon, 9 Jul 2018 15:24:27 +0000 (18:24 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Nov 2019 18:28:26 +0000 (19:28 +0100)
commit 7e34f4e4aad3fd34c02b294a3cf2321adf5b4438 upstream.

In some circumstances the RC6 context can get corrupted. We can detect
this and take the required action, that is disable RC6 and runtime PM.
The HW recovers from the corrupted state after a system suspend/resume
cycle, so detect the recovery and re-enable RC6 and runtime PM.

v2: rebase (Mika)
v3:
- Move intel_suspend_gt_powersave() to the end of the GEM suspend
  sequence.
- Add commit message.
v4:
- Rebased on intel_uncore_forcewake_put(i915->uncore, ...) API
  change.
v5: rebased on gem/gt split (Mika)

Signed-off-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/i915/gt/intel_gt_pm.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_pm.h

index 9f8f7f54191f06fbdca97dc8dbcae4a9d8a74ee2..3f6f42592708b0efc0c55e1b73a0e3e6a7a632e9 100644 (file)
@@ -36,6 +36,9 @@ static int intel_gt_unpark(struct intel_wakeref *wf)
        i915->gt.awake = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
        GEM_BUG_ON(!i915->gt.awake);
 
+       if (NEEDS_RC6_CTX_CORRUPTION_WA(i915))
+               intel_uncore_forcewake_get(&i915->uncore, FORCEWAKE_ALL);
+
        intel_enable_gt_powersave(i915);
 
        i915_update_gfx_val(i915);
@@ -70,6 +73,11 @@ static int intel_gt_park(struct intel_wakeref *wf)
        if (INTEL_GEN(i915) >= 6)
                gen6_rps_idle(i915);
 
+       if (NEEDS_RC6_CTX_CORRUPTION_WA(i915)) {
+               intel_rc6_ctx_wa_check(i915);
+               intel_uncore_forcewake_put(&i915->uncore, FORCEWAKE_ALL);
+       }
+
        GEM_BUG_ON(!wakeref);
        intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ, wakeref);
 
index 89efe6ce14d4722238dad04068622d269ce17457..b6d51514cf9ce35371a788408d0e569890fb91ea 100644 (file)
@@ -2156,6 +2156,8 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
 
        i915_gem_suspend_late(dev_priv);
 
+       intel_rc6_ctx_wa_suspend(dev_priv);
+
        intel_uncore_suspend(&dev_priv->uncore);
 
        intel_power_domains_suspend(dev_priv,
@@ -2372,6 +2374,8 @@ static int i915_drm_resume_early(struct drm_device *dev)
 
        intel_power_domains_resume(dev_priv);
 
+       intel_rc6_ctx_wa_resume(dev_priv);
+
        intel_gt_sanitize(dev_priv, true);
 
        enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
index 08fe13b7769a1edba668ed1a9a8f44f20a05554f..a992f0749859e2dffed7b66f6fc77e6ee006fbe1 100644 (file)
@@ -696,6 +696,8 @@ struct intel_rps {
 
 struct intel_rc6 {
        bool enabled;
+       bool ctx_corrupted;
+       intel_wakeref_t ctx_corrupted_wakeref;
        u64 prev_hw_residency[4];
        u64 cur_residency[4];
 };
@@ -2288,10 +2290,12 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
 /* Early gen2 have a totally busted CS tlb and require pinned batches. */
 #define HAS_BROKEN_CS_TLB(dev_priv)    (IS_I830(dev_priv) || IS_I845G(dev_priv))
 
+#define NEEDS_RC6_CTX_CORRUPTION_WA(dev_priv)  \
+       (IS_BROADWELL(dev_priv) || IS_GEN(dev_priv, 9))
+
 /* WaRsDisableCoarsePowerGating:skl,cnl */
 #define NEEDS_WaRsDisableCoarsePowerGating(dev_priv) \
-       (IS_CANNONLAKE(dev_priv) || \
-        IS_SKL_GT3(dev_priv) || IS_SKL_GT4(dev_priv))
+       (IS_CANNONLAKE(dev_priv) || IS_GEN(dev_priv, 9))
 
 #define HAS_GMBUS_IRQ(dev_priv) (INTEL_GEN(dev_priv) >= 4)
 #define HAS_GMBUS_BURST_READ(dev_priv) (INTEL_GEN(dev_priv) >= 10 || \
index cf00cc592ce63a9407aed27670a17b1e48c631a2..177a26275811d4a6b4c0f374db70538554efa664 100644 (file)
@@ -493,6 +493,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define   ECOCHK_PPGTT_WT_HSW          (0x2 << 3)
 #define   ECOCHK_PPGTT_WB_HSW          (0x3 << 3)
 
+#define GEN8_RC6_CTX_INFO              _MMIO(0x8504)
+
 #define GAC_ECO_BITS                   _MMIO(0x14090)
 #define   ECOBITS_SNB_BIT              (1 << 13)
 #define   ECOBITS_PPGTT_CACHE64B       (3 << 8)
index df6f740dd63d51b42b8d3c64728587bda50c6f7c..9546900fd72b67768c9ef4195737a850ef22e788 100644 (file)
@@ -8564,6 +8564,95 @@ static void intel_init_emon(struct drm_i915_private *dev_priv)
        dev_priv->ips.corr = (lcfuse & LCFUSE_HIV_MASK);
 }
 
+static bool intel_rc6_ctx_corrupted(struct drm_i915_private *dev_priv)
+{
+       return !I915_READ(GEN8_RC6_CTX_INFO);
+}
+
+static void intel_rc6_ctx_wa_init(struct drm_i915_private *i915)
+{
+       if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
+               return;
+
+       if (intel_rc6_ctx_corrupted(i915)) {
+               DRM_INFO("RC6 context corrupted, disabling runtime power management\n");
+               i915->gt_pm.rc6.ctx_corrupted = true;
+               i915->gt_pm.rc6.ctx_corrupted_wakeref =
+                       intel_runtime_pm_get(&i915->runtime_pm);
+       }
+}
+
+static void intel_rc6_ctx_wa_cleanup(struct drm_i915_private *i915)
+{
+       if (i915->gt_pm.rc6.ctx_corrupted) {
+               intel_runtime_pm_put(&i915->runtime_pm,
+                                    i915->gt_pm.rc6.ctx_corrupted_wakeref);
+               i915->gt_pm.rc6.ctx_corrupted = false;
+       }
+}
+
+/**
+ * intel_rc6_ctx_wa_suspend - system suspend sequence for the RC6 CTX WA
+ * @i915: i915 device
+ *
+ * Perform any steps needed to clean up the RC6 CTX WA before system suspend.
+ */
+void intel_rc6_ctx_wa_suspend(struct drm_i915_private *i915)
+{
+       if (i915->gt_pm.rc6.ctx_corrupted)
+               intel_runtime_pm_put(&i915->runtime_pm,
+                                    i915->gt_pm.rc6.ctx_corrupted_wakeref);
+}
+
+/**
+ * intel_rc6_ctx_wa_resume - system resume sequence for the RC6 CTX WA
+ * @i915: i915 device
+ *
+ * Perform any steps needed to re-init the RC6 CTX WA after system resume.
+ */
+void intel_rc6_ctx_wa_resume(struct drm_i915_private *i915)
+{
+       if (!i915->gt_pm.rc6.ctx_corrupted)
+               return;
+
+       if (intel_rc6_ctx_corrupted(i915)) {
+               i915->gt_pm.rc6.ctx_corrupted_wakeref =
+                       intel_runtime_pm_get(&i915->runtime_pm);
+               return;
+       }
+
+       DRM_INFO("RC6 context restored, re-enabling runtime power management\n");
+       i915->gt_pm.rc6.ctx_corrupted = false;
+}
+
+static void intel_disable_rc6(struct drm_i915_private *dev_priv);
+
+/**
+ * intel_rc6_ctx_wa_check - check for a new RC6 CTX corruption
+ * @i915: i915 device
+ *
+ * Check if an RC6 CTX corruption has happened since the last check and if so
+ * disable RC6 and runtime power management.
+*/
+void intel_rc6_ctx_wa_check(struct drm_i915_private *i915)
+{
+       if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
+               return;
+
+       if (i915->gt_pm.rc6.ctx_corrupted)
+               return;
+
+       if (!intel_rc6_ctx_corrupted(i915))
+               return;
+
+       DRM_NOTE("RC6 context corruption, disabling runtime power management\n");
+
+       intel_disable_rc6(i915);
+       i915->gt_pm.rc6.ctx_corrupted = true;
+       i915->gt_pm.rc6.ctx_corrupted_wakeref =
+               intel_runtime_pm_get_noresume(&i915->runtime_pm);
+}
+
 void intel_init_gt_powersave(struct drm_i915_private *dev_priv)
 {
        struct intel_rps *rps = &dev_priv->gt_pm.rps;
@@ -8577,6 +8666,8 @@ void intel_init_gt_powersave(struct drm_i915_private *dev_priv)
                pm_runtime_get(&dev_priv->drm.pdev->dev);
        }
 
+       intel_rc6_ctx_wa_init(dev_priv);
+
        /* Initialize RPS limits (for userspace) */
        if (IS_CHERRYVIEW(dev_priv))
                cherryview_init_gt_powersave(dev_priv);
@@ -8615,6 +8706,8 @@ void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv)
        if (IS_VALLEYVIEW(dev_priv))
                valleyview_cleanup_gt_powersave(dev_priv);
 
+       intel_rc6_ctx_wa_cleanup(dev_priv);
+
        if (!HAS_RC6(dev_priv))
                pm_runtime_put(&dev_priv->drm.pdev->dev);
 }
@@ -8643,7 +8736,7 @@ static inline void intel_disable_llc_pstate(struct drm_i915_private *i915)
        i915->gt_pm.llc_pstate.enabled = false;
 }
 
-static void intel_disable_rc6(struct drm_i915_private *dev_priv)
+static void __intel_disable_rc6(struct drm_i915_private *dev_priv)
 {
        lockdep_assert_held(&dev_priv->gt_pm.rps.lock);
 
@@ -8662,6 +8755,13 @@ static void intel_disable_rc6(struct drm_i915_private *dev_priv)
        dev_priv->gt_pm.rc6.enabled = false;
 }
 
+static void intel_disable_rc6(struct drm_i915_private *dev_priv)
+{
+       mutex_lock(&dev_priv->gt_pm.rps.lock);
+       __intel_disable_rc6(dev_priv);
+       mutex_unlock(&dev_priv->gt_pm.rps.lock);
+}
+
 static void intel_disable_rps(struct drm_i915_private *dev_priv)
 {
        lockdep_assert_held(&dev_priv->gt_pm.rps.lock);
@@ -8687,7 +8787,7 @@ void intel_disable_gt_powersave(struct drm_i915_private *dev_priv)
 {
        mutex_lock(&dev_priv->gt_pm.rps.lock);
 
-       intel_disable_rc6(dev_priv);
+       __intel_disable_rc6(dev_priv);
        intel_disable_rps(dev_priv);
        if (HAS_LLC(dev_priv))
                intel_disable_llc_pstate(dev_priv);
@@ -8714,6 +8814,9 @@ static void intel_enable_rc6(struct drm_i915_private *dev_priv)
        if (dev_priv->gt_pm.rc6.enabled)
                return;
 
+       if (dev_priv->gt_pm.rc6.ctx_corrupted)
+               return;
+
        if (IS_CHERRYVIEW(dev_priv))
                cherryview_enable_rc6(dev_priv);
        else if (IS_VALLEYVIEW(dev_priv))
index 1b489fa399e1d987e25ef2b5878fd8bd4809929a..4ccb5a53b61c769628b308d6e5a26c96406212a2 100644 (file)
@@ -36,6 +36,9 @@ void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv);
 void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv);
 void intel_enable_gt_powersave(struct drm_i915_private *dev_priv);
 void intel_disable_gt_powersave(struct drm_i915_private *dev_priv);
+void intel_rc6_ctx_wa_check(struct drm_i915_private *i915);
+void intel_rc6_ctx_wa_suspend(struct drm_i915_private *i915);
+void intel_rc6_ctx_wa_resume(struct drm_i915_private *i915);
 void gen6_rps_busy(struct drm_i915_private *dev_priv);
 void gen6_rps_idle(struct drm_i915_private *dev_priv);
 void gen6_rps_boost(struct i915_request *rq);