283 lines
8.7 KiB
Diff
283 lines
8.7 KiB
Diff
From: Imre Deak <imre.deak@intel.com>
|
|
Date: Mon, 9 Jul 2018 18:24:27 +0300
|
|
Subject: drm/i915/gen8+: Add RC6 CTX corruption WA
|
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0154
|
|
|
|
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>
|
|
---
|
|
drivers/gpu/drm/i915/i915_drv.c | 3 +
|
|
drivers/gpu/drm/i915/i915_drv.h | 7 +-
|
|
drivers/gpu/drm/i915/i915_gem.c | 8 +++
|
|
drivers/gpu/drm/i915/i915_reg.h | 2 +
|
|
drivers/gpu/drm/i915/intel_drv.h | 3 +
|
|
drivers/gpu/drm/i915/intel_pm.c | 107 ++++++++++++++++++++++++++++++-
|
|
6 files changed, 126 insertions(+), 4 deletions(-)
|
|
|
|
--- a/drivers/gpu/drm/i915/i915_drv.c
|
|
+++ b/drivers/gpu/drm/i915/i915_drv.c
|
|
@@ -1621,6 +1621,7 @@ static int i915_drm_suspend_late(struct
|
|
i915_gem_suspend_late(dev_priv);
|
|
|
|
intel_display_set_init_power(dev_priv, false);
|
|
+ i915_rc6_ctx_wa_suspend(dev_priv);
|
|
intel_uncore_suspend(dev_priv);
|
|
|
|
/*
|
|
@@ -1847,6 +1848,8 @@ static int i915_drm_resume_early(struct
|
|
else
|
|
intel_display_set_init_power(dev_priv, true);
|
|
|
|
+ i915_rc6_ctx_wa_resume(dev_priv);
|
|
+
|
|
intel_engines_sanitize(dev_priv);
|
|
|
|
enable_rpm_wakeref_asserts(dev_priv);
|
|
--- a/drivers/gpu/drm/i915/i915_drv.h
|
|
+++ b/drivers/gpu/drm/i915/i915_drv.h
|
|
@@ -801,6 +801,7 @@ struct intel_rps {
|
|
|
|
struct intel_rc6 {
|
|
bool enabled;
|
|
+ bool ctx_corrupted;
|
|
u64 prev_hw_residency[4];
|
|
u64 cur_residency[4];
|
|
};
|
|
@@ -2557,10 +2558,12 @@ intel_info(const struct drm_i915_private
|
|
/* 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) || INTEL_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) || INTEL_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 || \
|
|
--- a/drivers/gpu/drm/i915/i915_gem.c
|
|
+++ b/drivers/gpu/drm/i915/i915_gem.c
|
|
@@ -174,6 +174,11 @@ static u32 __i915_gem_park(struct drm_i9
|
|
if (INTEL_GEN(i915) >= 6)
|
|
gen6_rps_idle(i915);
|
|
|
|
+ if (NEEDS_RC6_CTX_CORRUPTION_WA(i915)) {
|
|
+ i915_rc6_ctx_wa_check(i915);
|
|
+ intel_uncore_forcewake_put(i915, FORCEWAKE_ALL);
|
|
+ }
|
|
+
|
|
intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ);
|
|
|
|
intel_runtime_pm_put(i915);
|
|
@@ -220,6 +225,9 @@ void i915_gem_unpark(struct drm_i915_pri
|
|
*/
|
|
intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
|
|
|
|
+ if (NEEDS_RC6_CTX_CORRUPTION_WA(i915))
|
|
+ intel_uncore_forcewake_get(i915, FORCEWAKE_ALL);
|
|
+
|
|
i915->gt.awake = true;
|
|
if (unlikely(++i915->gt.epoch == 0)) /* keep 0 as invalid */
|
|
i915->gt.epoch = 1;
|
|
--- a/drivers/gpu/drm/i915/i915_reg.h
|
|
+++ b/drivers/gpu/drm/i915/i915_reg.h
|
|
@@ -387,6 +387,8 @@ static inline bool i915_mmio_reg_valid(i
|
|
#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)
|
|
--- a/drivers/gpu/drm/i915/intel_drv.h
|
|
+++ b/drivers/gpu/drm/i915/intel_drv.h
|
|
@@ -2064,6 +2064,9 @@ void intel_sanitize_gt_powersave(struct
|
|
void intel_enable_gt_powersave(struct drm_i915_private *dev_priv);
|
|
void intel_disable_gt_powersave(struct drm_i915_private *dev_priv);
|
|
void intel_suspend_gt_powersave(struct drm_i915_private *dev_priv);
|
|
+bool i915_rc6_ctx_wa_check(struct drm_i915_private *i915);
|
|
+void i915_rc6_ctx_wa_suspend(struct drm_i915_private *i915);
|
|
+void i915_rc6_ctx_wa_resume(struct drm_i915_private *i915);
|
|
void gen6_rps_busy(struct drm_i915_private *dev_priv);
|
|
void gen6_rps_reset_ei(struct drm_i915_private *dev_priv);
|
|
void gen6_rps_idle(struct drm_i915_private *dev_priv);
|
|
--- a/drivers/gpu/drm/i915/intel_pm.c
|
|
+++ b/drivers/gpu/drm/i915/intel_pm.c
|
|
@@ -8196,6 +8196,95 @@ static void intel_init_emon(struct drm_i
|
|
dev_priv->ips.corr = (lcfuse & LCFUSE_HIV_MASK);
|
|
}
|
|
|
|
+static bool i915_rc6_ctx_corrupted(struct drm_i915_private *dev_priv)
|
|
+{
|
|
+ return !I915_READ(GEN8_RC6_CTX_INFO);
|
|
+}
|
|
+
|
|
+static void i915_rc6_ctx_wa_init(struct drm_i915_private *i915)
|
|
+{
|
|
+ if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
|
|
+ return;
|
|
+
|
|
+ if (i915_rc6_ctx_corrupted(i915)) {
|
|
+ DRM_INFO("RC6 context corrupted, disabling runtime power management\n");
|
|
+ i915->gt_pm.rc6.ctx_corrupted = true;
|
|
+ intel_runtime_pm_get(i915);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void i915_rc6_ctx_wa_cleanup(struct drm_i915_private *i915)
|
|
+{
|
|
+ if (i915->gt_pm.rc6.ctx_corrupted) {
|
|
+ intel_runtime_pm_put(i915);
|
|
+ i915->gt_pm.rc6.ctx_corrupted = false;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * i915_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 i915_rc6_ctx_wa_suspend(struct drm_i915_private *i915)
|
|
+{
|
|
+ if (i915->gt_pm.rc6.ctx_corrupted)
|
|
+ intel_runtime_pm_put(i915);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * i915_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 i915_rc6_ctx_wa_resume(struct drm_i915_private *i915)
|
|
+{
|
|
+ if (!i915->gt_pm.rc6.ctx_corrupted)
|
|
+ return;
|
|
+
|
|
+ if (i915_rc6_ctx_corrupted(i915)) {
|
|
+ intel_runtime_pm_get(i915);
|
|
+ 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);
|
|
+
|
|
+/**
|
|
+ * i915_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.
|
|
+ *
|
|
+ * Return false if no context corruption has happened since the last call of
|
|
+ * this function, true otherwise.
|
|
+*/
|
|
+bool i915_rc6_ctx_wa_check(struct drm_i915_private *i915)
|
|
+{
|
|
+ if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
|
|
+ return false;
|
|
+
|
|
+ if (i915->gt_pm.rc6.ctx_corrupted)
|
|
+ return false;
|
|
+
|
|
+ if (!i915_rc6_ctx_corrupted(i915))
|
|
+ return false;
|
|
+
|
|
+ DRM_NOTE("RC6 context corruption, disabling runtime power management\n");
|
|
+
|
|
+ intel_disable_rc6(i915);
|
|
+ i915->gt_pm.rc6.ctx_corrupted = true;
|
|
+ intel_runtime_pm_get_noresume(i915);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
void intel_init_gt_powersave(struct drm_i915_private *dev_priv)
|
|
{
|
|
struct intel_rps *rps = &dev_priv->gt_pm.rps;
|
|
@@ -8211,6 +8300,8 @@ void intel_init_gt_powersave(struct drm_
|
|
|
|
mutex_lock(&dev_priv->pcu_lock);
|
|
|
|
+ i915_rc6_ctx_wa_init(dev_priv);
|
|
+
|
|
/* Initialize RPS limits (for userspace) */
|
|
if (IS_CHERRYVIEW(dev_priv))
|
|
cherryview_init_gt_powersave(dev_priv);
|
|
@@ -8257,6 +8348,8 @@ void intel_cleanup_gt_powersave(struct d
|
|
if (IS_VALLEYVIEW(dev_priv))
|
|
valleyview_cleanup_gt_powersave(dev_priv);
|
|
|
|
+ i915_rc6_ctx_wa_cleanup(dev_priv);
|
|
+
|
|
if (!HAS_RC6(dev_priv))
|
|
intel_runtime_pm_put(dev_priv);
|
|
}
|
|
@@ -8301,7 +8394,7 @@ static inline void intel_disable_llc_pst
|
|
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->pcu_lock);
|
|
|
|
@@ -8320,6 +8413,13 @@ static void intel_disable_rc6(struct drm
|
|
dev_priv->gt_pm.rc6.enabled = false;
|
|
}
|
|
|
|
+static void intel_disable_rc6(struct drm_i915_private *dev_priv)
|
|
+{
|
|
+ mutex_lock(&dev_priv->pcu_lock);
|
|
+ __intel_disable_rc6(dev_priv);
|
|
+ mutex_unlock(&dev_priv->pcu_lock);
|
|
+}
|
|
+
|
|
static void intel_disable_rps(struct drm_i915_private *dev_priv)
|
|
{
|
|
lockdep_assert_held(&dev_priv->pcu_lock);
|
|
@@ -8345,7 +8445,7 @@ void intel_disable_gt_powersave(struct d
|
|
{
|
|
mutex_lock(&dev_priv->pcu_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);
|
|
@@ -8372,6 +8472,9 @@ static void intel_enable_rc6(struct drm_
|
|
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))
|