Commit a5266db4 authored by Hans de Goede's avatar Hans de Goede Committed by Hans de Goede

drm/i915: Acquire PUNIT->PMIC bus for intel_uncore_forcewake_reset()

intel_uncore_forcewake_reset() does forcewake puts and gets as such
we need to make sure that no-one tries to access the PUNIT->PMIC bus
(on systems where this bus is shared) while it runs, otherwise bad
things happen.

Normally this is taken care of by the i915_pmic_bus_access_notifier()
which does an intel_uncore_forcewake_get(FORCEWAKE_ALL) when some other
driver tries to access the PMIC bus, so that later forcewake gets are
no-ops (for the duration of the bus access).

But intel_uncore_forcewake_reset gets called in 3 cases:
1) Before registering the pmic_bus_access_notifier
2) After unregistering the pmic_bus_access_notifier
3) To reset forcewake state on a GPU reset

In all 3 cases the i915_pmic_bus_access_notifier() protection is
insufficient.

This commit fixes this race by calling iosf_mbi_punit_acquire() before
calling intel_uncore_forcewake_reset(). In the case where it is called
directly after unregistering the pmic_bus_access_notifier, we need to
hold the punit-lock over both calls to avoid a race where
intel_uncore_fw_release_timer() may execute between the 2 calls.
Reviewed-by: default avatarImre Deak <imre.deak@intel.com>
Acked-by: default avatarIngo Molnar <mingo@kernel.org>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171019111620.26761-3-hdegoede@redhat.com
parent af0ab55f
...@@ -345,6 +345,7 @@ intel_uncore_fw_release_timer(struct hrtimer *timer) ...@@ -345,6 +345,7 @@ intel_uncore_fw_release_timer(struct hrtimer *timer)
return HRTIMER_NORESTART; return HRTIMER_NORESTART;
} }
/* Note callers must have acquired the PUNIT->PMIC bus, before calling this. */
static void intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv, static void intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv,
bool restore) bool restore)
{ {
...@@ -353,6 +354,8 @@ static void intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv, ...@@ -353,6 +354,8 @@ static void intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv,
int retry_count = 100; int retry_count = 100;
enum forcewake_domains fw, active_domains; enum forcewake_domains fw, active_domains;
iosf_mbi_assert_punit_acquired();
/* Hold uncore.lock across reset to prevent any register access /* Hold uncore.lock across reset to prevent any register access
* with forcewake not set correctly. Wait until all pending * with forcewake not set correctly. Wait until all pending
* timers are run before holding. * timers are run before holding.
...@@ -532,14 +535,18 @@ static void __intel_uncore_early_sanitize(struct drm_i915_private *dev_priv, ...@@ -532,14 +535,18 @@ static void __intel_uncore_early_sanitize(struct drm_i915_private *dev_priv,
GT_FIFO_CTL_RC6_POLICY_STALL); GT_FIFO_CTL_RC6_POLICY_STALL);
} }
iosf_mbi_punit_acquire();
intel_uncore_forcewake_reset(dev_priv, restore_forcewake); intel_uncore_forcewake_reset(dev_priv, restore_forcewake);
iosf_mbi_punit_release();
} }
void intel_uncore_suspend(struct drm_i915_private *dev_priv) void intel_uncore_suspend(struct drm_i915_private *dev_priv)
{ {
iosf_mbi_unregister_pmic_bus_access_notifier( iosf_mbi_punit_acquire();
iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
&dev_priv->uncore.pmic_bus_access_nb); &dev_priv->uncore.pmic_bus_access_nb);
intel_uncore_forcewake_reset(dev_priv, false); intel_uncore_forcewake_reset(dev_priv, false);
iosf_mbi_punit_release();
} }
void intel_uncore_resume_early(struct drm_i915_private *dev_priv) void intel_uncore_resume_early(struct drm_i915_private *dev_priv)
...@@ -1419,12 +1426,14 @@ void intel_uncore_init(struct drm_i915_private *dev_priv) ...@@ -1419,12 +1426,14 @@ void intel_uncore_init(struct drm_i915_private *dev_priv)
void intel_uncore_fini(struct drm_i915_private *dev_priv) void intel_uncore_fini(struct drm_i915_private *dev_priv)
{ {
iosf_mbi_unregister_pmic_bus_access_notifier(
&dev_priv->uncore.pmic_bus_access_nb);
/* Paranoia: make sure we have disabled everything before we exit. */ /* Paranoia: make sure we have disabled everything before we exit. */
intel_uncore_sanitize(dev_priv); intel_uncore_sanitize(dev_priv);
iosf_mbi_punit_acquire();
iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
&dev_priv->uncore.pmic_bus_access_nb);
intel_uncore_forcewake_reset(dev_priv, false); intel_uncore_forcewake_reset(dev_priv, false);
iosf_mbi_punit_release();
} }
static const struct reg_whitelist { static const struct reg_whitelist {
......
...@@ -148,7 +148,10 @@ static int intel_uncore_check_forcewake_domains(struct drm_i915_private *dev_pri ...@@ -148,7 +148,10 @@ static int intel_uncore_check_forcewake_domains(struct drm_i915_private *dev_pri
for_each_set_bit(offset, valid, FW_RANGE) { for_each_set_bit(offset, valid, FW_RANGE) {
i915_reg_t reg = { offset }; i915_reg_t reg = { offset };
iosf_mbi_punit_acquire();
intel_uncore_forcewake_reset(dev_priv, false); intel_uncore_forcewake_reset(dev_priv, false);
iosf_mbi_punit_release();
check_for_unclaimed_mmio(dev_priv); check_for_unclaimed_mmio(dev_priv);
(void)I915_READ(reg); (void)I915_READ(reg);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment