]> git.baikalelectronics.ru Git - kernel.git/commitdiff
drm/i915/gen8+: Add RC6 CTX corruption WA
authorImre Deak <imre.deak@intel.com>
Thu, 17 Oct 2019 13:38:31 +0000 (16:38 +0300)
committerDave Airlie <airlied@redhat.com>
Thu, 14 Nov 2019 00:51:54 +0000 (10:51 +1000)
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 latest upstream gt_pm refactoring.
v6:
- s/i915_rc6_/intel_rc6_/
- Don't return a value from i915_rc6_ctx_wa_check().
v7:
- Rebased on latest gt rc6 refactoring.

Signed-off-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
[airlied: pull this later version of this patch into drm-next
to make resolving the conflict mess easier.]
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/i915/gt/intel_gt_pm.c
drivers/gpu/drm/i915/gt/intel_rc6.c
drivers/gpu/drm/i915/gt/intel_rc6.h
drivers/gpu/drm/i915/gt/intel_rc6_types.h
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h

index 060a27d9af34de18a07c5944a7db60ee2ea4c76f..6187cdd066465df2ed67eb6bca72526bb47d6a1c 100644 (file)
@@ -61,6 +61,9 @@ static int __gt_unpark(struct intel_wakeref *wf)
        gt->awake = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
        GEM_BUG_ON(!gt->awake);
 
+       if (NEEDS_RC6_CTX_CORRUPTION_WA(i915))
+               intel_uncore_forcewake_get(&i915->uncore, FORCEWAKE_ALL);
+
        intel_rps_unpark(&gt->rps);
        i915_pmu_gt_unparked(i915);
 
@@ -86,6 +89,11 @@ static int __gt_park(struct intel_wakeref *wf)
        /* Everything switched off, flush any residual interrupt just in case */
        intel_synchronize_irq(i915);
 
+       if (NEEDS_RC6_CTX_CORRUPTION_WA(i915)) {
+               intel_rc6_ctx_wa_check(&i915->gt.rc6);
+               intel_uncore_forcewake_put(&i915->uncore, FORCEWAKE_ALL);
+       }
+
        GEM_BUG_ON(!wakeref);
        intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ, wakeref);
 
index 5ad4a92a9582da016134c3e05560cdc8256eacce..4bbf28ce29c44ebb6a18a3f75d8b21b64e2e4e42 100644 (file)
@@ -486,6 +486,66 @@ static void rpm_put(struct intel_rc6 *rc6)
        rc6->wakeref = false;
 }
 
+static bool intel_rc6_ctx_corrupted(struct intel_rc6 *rc6)
+{
+       return !intel_uncore_read(rc6_to_uncore(rc6), GEN8_RC6_CTX_INFO);
+}
+
+static void intel_rc6_ctx_wa_init(struct intel_rc6 *rc6)
+{
+       struct drm_i915_private *i915 = rc6_to_i915(rc6);
+
+       if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
+               return;
+
+       if (intel_rc6_ctx_corrupted(rc6)) {
+               DRM_INFO("RC6 context corrupted, disabling runtime power management\n");
+               rc6->ctx_corrupted = true;
+       }
+}
+
+/**
+ * intel_rc6_ctx_wa_resume - system resume sequence for the RC6 CTX WA
+ * @rc6: rc6 state
+ *
+ * Perform any steps needed to re-init the RC6 CTX WA after system resume.
+ */
+void intel_rc6_ctx_wa_resume(struct intel_rc6 *rc6)
+{
+       if (rc6->ctx_corrupted && !intel_rc6_ctx_corrupted(rc6)) {
+               DRM_INFO("RC6 context restored, re-enabling runtime power management\n");
+               rc6->ctx_corrupted = false;
+       }
+}
+
+/**
+ * intel_rc6_ctx_wa_check - check for a new RC6 CTX corruption
+ * @rc6: rc6 state
+ *
+ * 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 intel_rc6 *rc6)
+{
+       struct drm_i915_private *i915 = rc6_to_i915(rc6);
+
+       if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
+               return;
+
+       if (rc6->ctx_corrupted)
+               return;
+
+       if (!intel_rc6_ctx_corrupted(rc6))
+               return;
+
+       DRM_NOTE("RC6 context corruption, disabling runtime power management\n");
+
+       intel_rc6_disable(rc6);
+       rc6->ctx_corrupted = true;
+
+       return;
+}
+
 static void __intel_rc6_disable(struct intel_rc6 *rc6)
 {
        struct drm_i915_private *i915 = rc6_to_i915(rc6);
@@ -510,6 +570,8 @@ void intel_rc6_init(struct intel_rc6 *rc6)
        if (!rc6_supported(rc6))
                return;
 
+       intel_rc6_ctx_wa_init(rc6);
+
        if (IS_CHERRYVIEW(i915))
                err = chv_rc6_init(rc6);
        else if (IS_VALLEYVIEW(i915))
@@ -544,6 +606,9 @@ void intel_rc6_enable(struct intel_rc6 *rc6)
 
        GEM_BUG_ON(rc6->enabled);
 
+       if (rc6->ctx_corrupted)
+               return;
+
        intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
 
        if (IS_CHERRYVIEW(i915))
index 5e6711f364575dc7847d4b08836728791a2988dd..1370f6834a4cc293beb7814d32605226f2a37308 100644 (file)
@@ -22,4 +22,7 @@ void intel_rc6_disable(struct intel_rc6 *rc6);
 u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, i915_reg_t reg);
 u64 intel_rc6_residency_us(struct intel_rc6 *rc6, i915_reg_t reg);
 
+void intel_rc6_ctx_wa_check(struct intel_rc6 *rc6);
+void intel_rc6_ctx_wa_resume(struct intel_rc6 *rc6);
+
 #endif /* INTEL_RC6_H */
index 214f354d6ae45f5e4bef5a39db14179eef8b0d3d..89ad5697a8d4cfb4b9a640189818ba413942a19e 100644 (file)
@@ -23,6 +23,7 @@ struct intel_rc6 {
        bool supported : 1;
        bool enabled : 1;
        bool wakeref : 1;
+       bool ctx_corrupted : 1;
 };
 
 #endif /* INTEL_RC6_TYPES_H */
index ccb5b566795f7837b7be3b02dbfd5ff1976f4735..87e05ca3646a37d1bb8afd8921549937520d285f 100644 (file)
@@ -63,6 +63,7 @@
 #include "gem/i915_gem_ioctls.h"
 #include "gt/intel_gt.h"
 #include "gt/intel_gt_pm.h"
+#include "gt/intel_rc6.h"
 
 #include "i915_debugfs.h"
 #include "i915_drv.h"
@@ -1819,6 +1820,8 @@ static int i915_drm_resume(struct drm_device *dev)
 
        disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
 
+       intel_rc6_ctx_wa_resume(&dev_priv->gt.rc6);
+
        intel_gt_sanitize(&dev_priv->gt, true);
 
        ret = i915_ggtt_enable_hw(dev_priv);
index 0567fe67e8c5ede6240e7fac5d515143b0ba7ef5..7765bd450797a240b270bda4b64d52bee037ca63 100644 (file)
@@ -1649,10 +1649,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 53c280c4e741c2c75b7fb6bee2291ee17eb33ea3..ae306dab57fadcaece8fd7f6fdbd3fc1947598d5 100644 (file)
@@ -474,6 +474,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)