Skip to content

Commit

Permalink
drm/i915: Restore user forcewake domains across suspend
Browse files Browse the repository at this point in the history
On suspend, we cancel the automatic forcewake and clear all other sources
of forcewake so the machine can sleep before we do suspend. However, we
expose the forcewake to userspace (only via debugfs, but nevertheless we
do) and want to restore that upon resume or else our accounting will be
off and we may not acquire the forcewake before we use it. So record
which domains we cleared on suspend and reacquire them early on resume.

v2: Hold the spinlock to appease our sanitychecks
v3: s/fw_domains_user/fw_domains_saved/ to convey intent more clearly

Reported-by: Imre Deak <imre.deak@linux.intel.com>
Fixes: b847305 ("drm/i915: Fix forcewake active domain tracking")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Imre Deak <imre.deak@linux.intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180808210842.3555-1-chris@chris-wilson.co.uk
  • Loading branch information
Chris Wilson committed Aug 9, 2018
1 parent d0e062e commit d60996a
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 21 deletions.
46 changes: 26 additions & 20 deletions drivers/gpu/drm/i915/intel_uncore.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,8 @@ intel_uncore_fw_release_timer(struct hrtimer *timer)
}

/* Note callers must have acquired the PUNIT->PMIC bus, before calling this. */
static void intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv,
bool restore)
static unsigned int
intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv)
{
unsigned long irqflags;
struct intel_uncore_forcewake_domain *domain;
Expand Down Expand Up @@ -422,20 +422,11 @@ static void intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv,
dev_priv->uncore.funcs.force_wake_put(dev_priv, fw);

fw_domains_reset(dev_priv, dev_priv->uncore.fw_domains);

if (restore) { /* If reset with a user forcewake, try to restore */
if (fw)
dev_priv->uncore.funcs.force_wake_get(dev_priv, fw);

if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv))
dev_priv->uncore.fifo_count =
fifo_free_entries(dev_priv);
}

if (!restore)
assert_forcewakes_inactive(dev_priv);
assert_forcewakes_inactive(dev_priv);

spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);

return fw; /* track the lost user forcewake domains */
}

static u64 gen9_edram_size(struct drm_i915_private *dev_priv)
Expand Down Expand Up @@ -544,7 +535,7 @@ check_for_unclaimed_mmio(struct drm_i915_private *dev_priv)
}

static void __intel_uncore_early_sanitize(struct drm_i915_private *dev_priv,
bool restore_forcewake)
unsigned int restore_forcewake)
{
/* clear out unclaimed reg detection bit */
if (check_for_unclaimed_mmio(dev_priv))
Expand All @@ -559,7 +550,17 @@ static void __intel_uncore_early_sanitize(struct drm_i915_private *dev_priv,
}

iosf_mbi_punit_acquire();
intel_uncore_forcewake_reset(dev_priv, restore_forcewake);
intel_uncore_forcewake_reset(dev_priv);
if (restore_forcewake) {
spin_lock_irq(&dev_priv->uncore.lock);
dev_priv->uncore.funcs.force_wake_get(dev_priv,
restore_forcewake);

if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv))
dev_priv->uncore.fifo_count =
fifo_free_entries(dev_priv);
spin_unlock_irq(&dev_priv->uncore.lock);
}
iosf_mbi_punit_release();
}

Expand All @@ -568,13 +569,18 @@ void intel_uncore_suspend(struct drm_i915_private *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);
dev_priv->uncore.fw_domains_saved =
intel_uncore_forcewake_reset(dev_priv);
iosf_mbi_punit_release();
}

void intel_uncore_resume_early(struct drm_i915_private *dev_priv)
{
__intel_uncore_early_sanitize(dev_priv, true);
unsigned int restore_forcewake;

restore_forcewake = fetch_and_zero(&dev_priv->uncore.fw_domains_saved);
__intel_uncore_early_sanitize(dev_priv, restore_forcewake);

iosf_mbi_register_pmic_bus_access_notifier(
&dev_priv->uncore.pmic_bus_access_nb);
i915_check_and_clear_faults(dev_priv);
Expand Down Expand Up @@ -1555,7 +1561,7 @@ void intel_uncore_init(struct drm_i915_private *dev_priv)

intel_uncore_edram_detect(dev_priv);
intel_uncore_fw_domains_init(dev_priv);
__intel_uncore_early_sanitize(dev_priv, false);
__intel_uncore_early_sanitize(dev_priv, 0);

dev_priv->uncore.unclaimed_mmio_check = 1;
dev_priv->uncore.pmic_bus_access_nb.notifier_call =
Expand Down Expand Up @@ -1642,7 +1648,7 @@ void intel_uncore_fini(struct drm_i915_private *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);
iosf_mbi_punit_release();
}

Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/intel_uncore.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ struct intel_uncore {

enum forcewake_domains fw_domains;
enum forcewake_domains fw_domains_active;
enum forcewake_domains fw_domains_saved; /* user domains saved for S3 */

u32 fw_set;
u32 fw_clear;
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/selftests/intel_uncore.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ static int intel_uncore_check_forcewake_domains(struct drm_i915_private *dev_pri
i915_reg_t reg = { offset };

iosf_mbi_punit_acquire();
intel_uncore_forcewake_reset(dev_priv, false);
intel_uncore_forcewake_reset(dev_priv);
iosf_mbi_punit_release();

check_for_unclaimed_mmio(dev_priv);
Expand Down

0 comments on commit d60996a

Please sign in to comment.