[16/21] drm/i915: Markup paired operations on display power domains

Submitted by Chris Wilson on Jan. 10, 2019, 10:11 a.m.

Details

Message ID 20190110101152.15651-17-chris@chris-wilson.co.uk
State Under Review
Headers show
Series "Series without cover letter" ( rev: 1 ) in Intel GFX

Not browsing as part of any series.

Commit Message

Chris Wilson Jan. 10, 2019, 10:11 a.m.
The majority of runtime-pm operations are bounded and scoped within a
function; these are easy to verify that the wakeref are handled
correctly. We can employ the compiler to help us, and reduce the number
of wakerefs tracked when debugging, by passing around cookies provided
by the various rpm_get functions to their rpm_put counterpart. This
makes the pairing explicit, and given the required wakeref cookie the
compiler can verify that we pass an initialised value to the rpm_put
(quite handy for double checking error paths).

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Jani Nikula <jani.nikula@intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c     | 35 ++++++------
 drivers/gpu/drm/i915/i915_drv.h         |  2 +
 drivers/gpu/drm/i915/i915_gem.c         |  4 +-
 drivers/gpu/drm/i915/icl_dsi.c          | 36 ++++++++-----
 drivers/gpu/drm/i915/intel_audio.c      |  3 +-
 drivers/gpu/drm/i915/intel_cdclk.c      | 10 ++--
 drivers/gpu/drm/i915/intel_crt.c        | 25 +++++----
 drivers/gpu/drm/i915/intel_csr.c        | 25 +++++++--
 drivers/gpu/drm/i915/intel_ddi.c        | 36 ++++++++-----
 drivers/gpu/drm/i915/intel_display.c    | 68 ++++++++++++++---------
 drivers/gpu/drm/i915/intel_dp.c         | 38 +++++++------
 drivers/gpu/drm/i915/intel_dpll_mgr.c   | 66 +++++++++++++++--------
 drivers/gpu/drm/i915/intel_drv.h        | 17 ++++--
 drivers/gpu/drm/i915/intel_dsi.h        |  1 +
 drivers/gpu/drm/i915/intel_hdmi.c       | 18 ++++---
 drivers/gpu/drm/i915/intel_i2c.c        | 20 +++----
 drivers/gpu/drm/i915/intel_lvds.c       |  8 +--
 drivers/gpu/drm/i915/intel_pipe_crc.c   |  6 ++-
 drivers/gpu/drm/i915/intel_pm.c         |  6 ++-
 drivers/gpu/drm/i915/intel_runtime_pm.c | 71 ++++++++++++++++---------
 drivers/gpu/drm/i915/intel_sprite.c     | 24 ++++++---
 drivers/gpu/drm/i915/intel_vdsc.c       |  4 +-
 drivers/gpu/drm/i915/vlv_dsi.c          | 14 +++--
 23 files changed, 347 insertions(+), 190 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 34cbd9a20583..b7dcacf2a5d3 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -626,10 +626,12 @@  static void gen8_display_interrupt_info(struct seq_file *m)
 
 	for_each_pipe(dev_priv, pipe) {
 		enum intel_display_power_domain power_domain;
+		intel_wakeref_t wakeref;
 
 		power_domain = POWER_DOMAIN_PIPE(pipe);
-		if (!intel_display_power_get_if_enabled(dev_priv,
-							power_domain)) {
+		wakeref = intel_display_power_get_if_enabled(dev_priv,
+							     power_domain);
+		if (!wakeref) {
 			seq_printf(m, "Pipe %c power disabled\n",
 				   pipe_name(pipe));
 			continue;
@@ -644,7 +646,7 @@  static void gen8_display_interrupt_info(struct seq_file *m)
 			   pipe_name(pipe),
 			   I915_READ(GEN8_DE_PIPE_IER(pipe)));
 
-		intel_display_power_put(dev_priv, power_domain);
+		intel_display_power_put(dev_priv, power_domain, wakeref);
 	}
 
 	seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
@@ -680,6 +682,8 @@  static int i915_interrupt_info(struct seq_file *m, void *data)
 	wakeref = intel_runtime_pm_get(dev_priv);
 
 	if (IS_CHERRYVIEW(dev_priv)) {
+		intel_wakeref_t pref;
+
 		seq_printf(m, "Master Interrupt Control:\t%08x\n",
 			   I915_READ(GEN8_MASTER_IRQ));
 
@@ -695,8 +699,9 @@  static int i915_interrupt_info(struct seq_file *m, void *data)
 			enum intel_display_power_domain power_domain;
 
 			power_domain = POWER_DOMAIN_PIPE(pipe);
-			if (!intel_display_power_get_if_enabled(dev_priv,
-								power_domain)) {
+			pref = intel_display_power_get_if_enabled(dev_priv,
+								  power_domain);
+			if (!pref) {
 				seq_printf(m, "Pipe %c power disabled\n",
 					   pipe_name(pipe));
 				continue;
@@ -706,17 +711,17 @@  static int i915_interrupt_info(struct seq_file *m, void *data)
 				   pipe_name(pipe),
 				   I915_READ(PIPESTAT(pipe)));
 
-			intel_display_power_put(dev_priv, power_domain);
+			intel_display_power_put(dev_priv, power_domain, pref);
 		}
 
-		intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+		pref = intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
 		seq_printf(m, "Port hotplug:\t%08x\n",
 			   I915_READ(PORT_HOTPLUG_EN));
 		seq_printf(m, "DPFLIPSTAT:\t%08x\n",
 			   I915_READ(VLV_DPFLIPSTAT));
 		seq_printf(m, "DPINVGTT:\t%08x\n",
 			   I915_READ(DPINVGTT));
-		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, pref);
 
 		for (i = 0; i < 4; i++) {
 			seq_printf(m, "GT Interrupt IMR %d:\t%08x\n",
@@ -779,10 +784,12 @@  static int i915_interrupt_info(struct seq_file *m, void *data)
 			   I915_READ(VLV_IMR));
 		for_each_pipe(dev_priv, pipe) {
 			enum intel_display_power_domain power_domain;
+			intel_wakeref_t pref;
 
 			power_domain = POWER_DOMAIN_PIPE(pipe);
-			if (!intel_display_power_get_if_enabled(dev_priv,
-								power_domain)) {
+			pref = intel_display_power_get_if_enabled(dev_priv,
+								  power_domain);
+			if (!pref) {
 				seq_printf(m, "Pipe %c power disabled\n",
 					   pipe_name(pipe));
 				continue;
@@ -791,7 +798,7 @@  static int i915_interrupt_info(struct seq_file *m, void *data)
 			seq_printf(m, "Pipe %c stat:\t%08x\n",
 				   pipe_name(pipe),
 				   I915_READ(PIPESTAT(pipe)));
-			intel_display_power_put(dev_priv, power_domain);
+			intel_display_power_put(dev_priv, power_domain, pref);
 		}
 
 		seq_printf(m, "Master IER:\t%08x\n",
@@ -1709,8 +1716,7 @@  static int i915_sr_status(struct seq_file *m, void *unused)
 	intel_wakeref_t wakeref;
 	bool sr_enabled = false;
 
-	wakeref = intel_runtime_pm_get(dev_priv);
-	intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
 
 	if (INTEL_GEN(dev_priv) >= 9)
 		/* no global SR status; inspect per-plane WM */;
@@ -1726,8 +1732,7 @@  static int i915_sr_status(struct seq_file *m, void *unused)
 	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
 		sr_enabled = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN;
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
-	intel_runtime_pm_put(dev_priv, wakeref);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
 
 	seq_printf(m, "self-refresh: %s\n", enableddisabled(sr_enabled));
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f0a405604b75..44c1b21febba 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -344,6 +344,7 @@  struct intel_csr {
 	uint32_t mmiodata[8];
 	uint32_t dc_state;
 	uint32_t allowed_dc_mask;
+	intel_wakeref_t wakeref;
 };
 
 enum i915_cache_level {
@@ -1982,6 +1983,7 @@  struct drm_i915_private {
 		 * is a slight delay before we do so.
 		 */
 		intel_wakeref_t awake;
+		intel_wakeref_t power;
 
 		/**
 		 * The number of times we have woken up.
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 67fd119bdad8..5ed1c8576525 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -176,7 +176,7 @@  static u32 __i915_gem_park(struct drm_i915_private *i915)
 	if (INTEL_GEN(i915) >= 6)
 		gen6_rps_idle(i915);
 
-	intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ);
+	intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ, i915->gt.power);
 
 	intel_runtime_pm_put(i915, wakeref);
 
@@ -221,7 +221,7 @@  void i915_gem_unpark(struct drm_i915_private *i915)
 	 * Work around it by grabbing a GT IRQ power domain whilst there is any
 	 * GT activity, preventing any DC state transitions.
 	 */
-	intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
+	i915->gt.power = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
 
 	if (unlikely(++i915->gt.epoch == 0)) /* keep 0 as invalid */
 		i915->gt.epoch = 1;
diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c
index 4dd793b78996..f3a5f03646ce 100644
--- a/drivers/gpu/drm/i915/icl_dsi.c
+++ b/drivers/gpu/drm/i915/icl_dsi.c
@@ -337,9 +337,11 @@  static void gen11_dsi_enable_io_power(struct intel_encoder *encoder)
 	}
 
 	for_each_dsi_port(port, intel_dsi->ports) {
-		intel_display_power_get(dev_priv, port == PORT_A ?
-					POWER_DOMAIN_PORT_DDI_A_IO :
-					POWER_DOMAIN_PORT_DDI_B_IO);
+		intel_dsi->io_wakeref[port] =
+			intel_display_power_get(dev_priv,
+						port == PORT_A ?
+						POWER_DOMAIN_PORT_DDI_A_IO :
+						POWER_DOMAIN_PORT_DDI_B_IO);
 	}
 }
 
@@ -1125,10 +1127,18 @@  static void gen11_dsi_disable_io_power(struct intel_encoder *encoder)
 	enum port port;
 	u32 tmp;
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_A_IO);
-
-	if (intel_dsi->dual_link)
-		intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_B_IO);
+	for_each_dsi_port(port, intel_dsi->ports) {
+		intel_wakeref_t wakeref;
+
+		wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
+		if (wakeref) {
+			intel_display_power_put(dev_priv,
+						port == PORT_A ?
+						POWER_DOMAIN_PORT_DDI_A_IO :
+						POWER_DOMAIN_PORT_DDI_B_IO,
+						wakeref);
+		}
+	}
 
 	/* set mode to DDI */
 	for_each_dsi_port(port, intel_dsi->ports) {
@@ -1229,13 +1239,15 @@  static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder,
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-	u32 tmp;
-	enum port port;
 	enum transcoder dsi_trans;
+	intel_wakeref_t wakeref;
+	enum port port;
 	bool ret = false;
+	u32 tmp;
 
-	if (!intel_display_power_get_if_enabled(dev_priv,
-						encoder->power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     encoder->power_domain);
+	if (!wakeref)
 		return false;
 
 	for_each_dsi_port(port, intel_dsi->ports) {
@@ -1260,7 +1272,7 @@  static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder,
 		ret = tmp & PIPECONF_ENABLE;
 	}
 out:
-	intel_display_power_put(dev_priv, encoder->power_domain);
+	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 202a58cf2d9f..de26cd0a5497 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -748,7 +748,8 @@  static void i915_audio_component_get_power(struct device *kdev)
 
 static void i915_audio_component_put_power(struct device *kdev)
 {
-	intel_display_power_put(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
+	intel_display_power_put_unchecked(kdev_to_i915(kdev),
+					  POWER_DOMAIN_AUDIO);
 }
 
 static void i915_audio_component_codec_wake_override(struct device *kdev,
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index 2021e484a287..73cb7250118e 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -520,6 +520,7 @@  static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
 {
 	int cdclk = cdclk_state->cdclk;
 	u32 val, cmd = cdclk_state->voltage_level;
+	intel_wakeref_t wakeref;
 
 	switch (cdclk) {
 	case 400000:
@@ -539,7 +540,7 @@  static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
 	 * a system suspend.  So grab the PIPE-A domain, which covers
 	 * the HW blocks needed for the following programming.
 	 */
-	intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
+	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
 
 	mutex_lock(&dev_priv->pcu_lock);
 	val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
@@ -593,7 +594,7 @@  static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
 
 	vlv_program_pfi_credits(dev_priv);
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A, wakeref);
 }
 
 static void chv_set_cdclk(struct drm_i915_private *dev_priv,
@@ -601,6 +602,7 @@  static void chv_set_cdclk(struct drm_i915_private *dev_priv,
 {
 	int cdclk = cdclk_state->cdclk;
 	u32 val, cmd = cdclk_state->voltage_level;
+	intel_wakeref_t wakeref;
 
 	switch (cdclk) {
 	case 333333:
@@ -619,7 +621,7 @@  static void chv_set_cdclk(struct drm_i915_private *dev_priv,
 	 * a system suspend.  So grab the PIPE-A domain, which covers
 	 * the HW blocks needed for the following programming.
 	 */
-	intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
+	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
 
 	mutex_lock(&dev_priv->pcu_lock);
 	val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
@@ -637,7 +639,7 @@  static void chv_set_cdclk(struct drm_i915_private *dev_priv,
 
 	vlv_program_pfi_credits(dev_priv);
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A, wakeref);
 }
 
 static int bdw_calc_cdclk(int min_cdclk)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 951e9bae6921..33bd2addcbdd 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -83,15 +83,17 @@  static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crt *crt = intel_encoder_to_crt(encoder);
+	intel_wakeref_t wakeref;
 	bool ret;
 
-	if (!intel_display_power_get_if_enabled(dev_priv,
-						encoder->power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     encoder->power_domain);
+	if (!wakeref)
 		return false;
 
 	ret = intel_crt_port_enabled(dev_priv, crt->adpa_reg, pipe);
 
-	intel_display_power_put(dev_priv, encoder->power_domain);
+	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
 
 	return ret;
 }
@@ -776,6 +778,7 @@  intel_crt_detect(struct drm_connector *connector,
 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
 	struct intel_crt *crt = intel_attached_crt(connector);
 	struct intel_encoder *intel_encoder = &crt->base;
+	intel_wakeref_t wakeref;
 	int status, ret;
 	struct intel_load_detect_pipe tmp;
 
@@ -784,7 +787,8 @@  intel_crt_detect(struct drm_connector *connector,
 		      force);
 
 	if (i915_modparams.load_detect_test) {
-		intel_display_power_get(dev_priv, intel_encoder->power_domain);
+		wakeref = intel_display_power_get(dev_priv,
+						  intel_encoder->power_domain);
 		goto load_detect;
 	}
 
@@ -792,7 +796,8 @@  intel_crt_detect(struct drm_connector *connector,
 	if (dmi_check_system(intel_spurious_crt_detect))
 		return connector_status_disconnected;
 
-	intel_display_power_get(dev_priv, intel_encoder->power_domain);
+	wakeref = intel_display_power_get(dev_priv,
+					  intel_encoder->power_domain);
 
 	if (I915_HAS_HOTPLUG(dev_priv)) {
 		/* We can not rely on the HPD pin always being correctly wired
@@ -847,7 +852,7 @@  intel_crt_detect(struct drm_connector *connector,
 	}
 
 out:
-	intel_display_power_put(dev_priv, intel_encoder->power_domain);
+	intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
 	return status;
 }
 
@@ -857,10 +862,12 @@  static int intel_crt_get_modes(struct drm_connector *connector)
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct intel_crt *crt = intel_attached_crt(connector);
 	struct intel_encoder *intel_encoder = &crt->base;
-	int ret;
+	intel_wakeref_t wakeref;
 	struct i2c_adapter *i2c;
+	int ret;
 
-	intel_display_power_get(dev_priv, intel_encoder->power_domain);
+	wakeref = intel_display_power_get(dev_priv,
+					  intel_encoder->power_domain);
 
 	i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
 	ret = intel_crt_ddc_get_modes(connector, i2c);
@@ -872,7 +879,7 @@  static int intel_crt_get_modes(struct drm_connector *connector)
 	ret = intel_crt_ddc_get_modes(connector, i2c);
 
 out:
-	intel_display_power_put(dev_priv, intel_encoder->power_domain);
+	intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index a516697bf57d..ea5fb64d33dd 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -409,6 +409,21 @@  static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
 	return memcpy(dmc_payload, &fw->data[readcount], nbytes);
 }
 
+static void intel_csr_runtime_pm_get(struct drm_i915_private *dev_priv)
+{
+	WARN_ON(dev_priv->csr.wakeref);
+	dev_priv->csr.wakeref =
+		intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+}
+
+static void intel_csr_runtime_pm_put(struct drm_i915_private *dev_priv)
+{
+	intel_wakeref_t wakeref __maybe_unused =
+		fetch_and_zero(&dev_priv->csr.wakeref);
+
+	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
+}
+
 static void csr_load_work_fn(struct work_struct *work)
 {
 	struct drm_i915_private *dev_priv;
@@ -424,8 +439,7 @@  static void csr_load_work_fn(struct work_struct *work)
 
 	if (dev_priv->csr.dmc_payload) {
 		intel_csr_load_program(dev_priv);
-
-		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+		intel_csr_runtime_pm_put(dev_priv);
 
 		DRM_INFO("Finished loading DMC firmware %s (v%u.%u)\n",
 			 dev_priv->csr.fw_path,
@@ -467,7 +481,7 @@  void intel_csr_ucode_init(struct drm_i915_private *dev_priv)
 	 * suspend as runtime suspend *requires* a working CSR for whatever
 	 * reason.
 	 */
-	intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+	intel_csr_runtime_pm_get(dev_priv);
 
 	if (INTEL_GEN(dev_priv) >= 12) {
 		/* Allow to load fw via parameter using the last known size */
@@ -538,7 +552,7 @@  void intel_csr_ucode_suspend(struct drm_i915_private *dev_priv)
 
 	/* Drop the reference held in case DMC isn't loaded. */
 	if (!dev_priv->csr.dmc_payload)
-		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+		intel_csr_runtime_pm_put(dev_priv);
 }
 
 /**
@@ -558,7 +572,7 @@  void intel_csr_ucode_resume(struct drm_i915_private *dev_priv)
 	 * loaded.
 	 */
 	if (!dev_priv->csr.dmc_payload)
-		intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+		intel_csr_runtime_pm_get(dev_priv);
 }
 
 /**
@@ -574,6 +588,7 @@  void intel_csr_ucode_fini(struct drm_i915_private *dev_priv)
 		return;
 
 	intel_csr_ucode_suspend(dev_priv);
+	WARN_ON(dev_priv->csr.wakeref);
 
 	kfree(dev_priv->csr.dmc_payload);
 }
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 2d6ed990a232..7f3cd055de50 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1860,12 +1860,14 @@  int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
 {
 	struct drm_device *dev = intel_encoder->base.dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
+	intel_wakeref_t wakeref;
 	enum pipe pipe = 0;
 	int ret = 0;
 	uint32_t tmp;
 
-	if (WARN_ON(!intel_display_power_get_if_enabled(dev_priv,
-						intel_encoder->power_domain)))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     intel_encoder->power_domain);
+	if (WARN_ON(!wakeref))
 		return -ENXIO;
 
 	if (WARN_ON(!intel_encoder->get_hw_state(intel_encoder, &pipe))) {
@@ -1880,7 +1882,7 @@  int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
 		tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
 	I915_WRITE(TRANS_DDI_FUNC_CTL(pipe), tmp);
 out:
-	intel_display_power_put(dev_priv, intel_encoder->power_domain);
+	intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
 	return ret;
 }
 
@@ -1891,13 +1893,15 @@  bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
 	struct intel_encoder *encoder = intel_connector->encoder;
 	int type = intel_connector->base.connector_type;
 	enum port port = encoder->port;
-	enum pipe pipe = 0;
 	enum transcoder cpu_transcoder;
+	intel_wakeref_t wakeref;
+	enum pipe pipe = 0;
 	uint32_t tmp;
 	bool ret;
 
-	if (!intel_display_power_get_if_enabled(dev_priv,
-						encoder->power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     encoder->power_domain);
+	if (!wakeref)
 		return false;
 
 	if (!encoder->get_hw_state(encoder, &pipe)) {
@@ -1939,7 +1943,7 @@  bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
 	}
 
 out:
-	intel_display_power_put(dev_priv, encoder->power_domain);
+	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
 
 	return ret;
 }
@@ -1950,6 +1954,7 @@  static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	enum port port = encoder->port;
+	intel_wakeref_t wakeref;
 	enum pipe p;
 	u32 tmp;
 	u8 mst_pipe_mask;
@@ -1957,8 +1962,9 @@  static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
 	*pipe_mask = 0;
 	*is_dp_mst = false;
 
-	if (!intel_display_power_get_if_enabled(dev_priv,
-						encoder->power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     encoder->power_domain);
+	if (!wakeref)
 		return;
 
 	tmp = I915_READ(DDI_BUF_CTL(port));
@@ -2029,7 +2035,7 @@  static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
 				  "(PHY_CTL %08x)\n", port_name(port), tmp);
 	}
 
-	intel_display_power_put(dev_priv, encoder->power_domain);
+	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
 }
 
 bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
@@ -3286,7 +3292,8 @@  static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
 	intel_edp_panel_vdd_on(intel_dp);
 	intel_edp_panel_off(intel_dp);
 
-	intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain);
+	intel_display_power_put_unchecked(dev_priv,
+					  dig_port->ddi_io_power_domain);
 
 	intel_ddi_clk_disable(encoder);
 }
@@ -3306,7 +3313,8 @@  static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
 
 	intel_disable_ddi_buf(encoder, old_crtc_state);
 
-	intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain);
+	intel_display_power_put_unchecked(dev_priv,
+					  dig_port->ddi_io_power_domain);
 
 	intel_ddi_clk_disable(encoder);
 
@@ -3626,8 +3634,8 @@  intel_ddi_post_pll_disable(struct intel_encoder *encoder,
 
 	if (intel_crtc_has_dp_encoder(crtc_state) ||
 	    intel_port_is_tc(dev_priv, encoder->port))
-		intel_display_power_put(dev_priv,
-					intel_ddi_main_link_aux_domain(dig_port));
+		intel_display_power_put_unchecked(dev_priv,
+						  intel_ddi_main_link_aux_domain(dig_port));
 }
 
 void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b0b8f9ffd873..36c56d1637b8 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1197,17 +1197,19 @@  void assert_pipe(struct drm_i915_private *dev_priv,
 	enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
 								      pipe);
 	enum intel_display_power_domain power_domain;
+	intel_wakeref_t wakeref;
 
 	/* we keep both pipes enabled on 830 */
 	if (IS_I830(dev_priv))
 		state = true;
 
 	power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
-	if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (wakeref) {
 		u32 val = I915_READ(PIPECONF(cpu_transcoder));
 		cur_state = !!(val & PIPECONF_ENABLE);
 
-		intel_display_power_put(dev_priv, power_domain);
+		intel_display_power_put(dev_priv, power_domain, wakeref);
 	} else {
 		cur_state = false;
 	}
@@ -3412,6 +3414,7 @@  static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	enum intel_display_power_domain power_domain;
 	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
+	intel_wakeref_t wakeref;
 	bool ret;
 	u32 val;
 
@@ -3421,7 +3424,8 @@  static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
 	 * display power wells.
 	 */
 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return false;
 
 	val = I915_READ(DSPCNTR(i9xx_plane));
@@ -3434,7 +3438,7 @@  static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
 		*pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
 			DISPPLANE_SEL_PIPE_SHIFT;
 
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
@@ -6107,7 +6111,7 @@  static void modeset_put_power_domains(struct drm_i915_private *dev_priv,
 	enum intel_display_power_domain domain;
 
 	for_each_power_domain(domain, domains)
-		intel_display_power_put(dev_priv, domain);
+		intel_display_power_put_unchecked(dev_priv, domain);
 }
 
 static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
@@ -6354,7 +6358,7 @@  static void intel_crtc_disable_noatomic(struct drm_crtc *crtc,
 
 	domains = intel_crtc->enabled_power_domains;
 	for_each_power_domain(domain, domains)
-		intel_display_power_put(dev_priv, domain);
+		intel_display_power_put_unchecked(dev_priv, domain);
 	intel_crtc->enabled_power_domains = 0;
 
 	dev_priv->active_crtcs &= ~(1 << intel_crtc->pipe);
@@ -7966,11 +7970,13 @@  static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
 {
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	enum intel_display_power_domain power_domain;
+	intel_wakeref_t wakeref;
 	uint32_t tmp;
 	bool ret;
 
 	power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return false;
 
 	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
@@ -8071,7 +8077,7 @@  static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
 	ret = true;
 
 out:
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
@@ -9038,11 +9044,13 @@  static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	enum intel_display_power_domain power_domain;
+	intel_wakeref_t wakeref;
 	uint32_t tmp;
 	bool ret;
 
 	power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return false;
 
 	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
@@ -9125,7 +9133,7 @@  static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
 	ret = true;
 
 out:
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
@@ -9734,7 +9742,7 @@  static bool haswell_get_pipe_config(struct intel_crtc *crtc,
 
 out:
 	for_each_power_domain(power_domain, power_domain_mask)
-		intel_display_power_put(dev_priv, power_domain);
+		intel_display_power_put_unchecked(dev_priv, power_domain);
 
 	return active;
 }
@@ -9984,17 +9992,19 @@  static bool i845_cursor_get_hw_state(struct intel_plane *plane,
 {
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	enum intel_display_power_domain power_domain;
+	intel_wakeref_t wakeref;
 	bool ret;
 
 	power_domain = POWER_DOMAIN_PIPE(PIPE_A);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return false;
 
 	ret = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE;
 
 	*pipe = PIPE_A;
 
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
@@ -10217,6 +10227,7 @@  static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
 {
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	enum intel_display_power_domain power_domain;
+	intel_wakeref_t wakeref;
 	bool ret;
 	u32 val;
 
@@ -10226,7 +10237,8 @@  static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
 	 * display power wells.
 	 */
 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return false;
 
 	val = I915_READ(CURCNTR(plane->pipe));
@@ -10239,7 +10251,7 @@  static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
 		*pipe = (val & MCURSOR_PIPE_SELECT_MASK) >>
 			MCURSOR_PIPE_SELECT_SHIFT;
 
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
@@ -12950,6 +12962,7 @@  static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 	struct drm_crtc *crtc;
 	struct intel_crtc *intel_crtc;
 	u64 put_domains[I915_MAX_PIPES] = {};
+	intel_wakeref_t wakeref = 0;
 	int i;
 
 	intel_atomic_commit_fence_wait(intel_state);
@@ -12957,7 +12970,7 @@  static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 	drm_atomic_helper_wait_for_dependencies(state);
 
 	if (intel_state->modeset)
-		intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
+		wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
 
 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
 		old_intel_crtc_state = to_intel_crtc_state(old_crtc_state);
@@ -13094,7 +13107,7 @@  static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 		 * the culprit.
 		 */
 		intel_uncore_arm_unclaimed_mmio_detection(dev_priv);
-		intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
+		intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET, wakeref);
 	}
 
 	/*
@@ -15496,19 +15509,25 @@  void i915_redisable_vga_power_on(struct drm_i915_private *dev_priv)
 
 void i915_redisable_vga(struct drm_i915_private *dev_priv)
 {
-	/* This function can be called both from intel_modeset_setup_hw_state or
+	intel_wakeref_t wakeref;
+
+	/*
+	 * This function can be called both from intel_modeset_setup_hw_state or
 	 * at a very early point in our resume sequence, where the power well
 	 * structures are not yet restored. Since this function is at a very
 	 * paranoid "someone might have enabled VGA while we were not looking"
 	 * level, just check if the power well is enabled instead of trying to
 	 * follow the "don't touch the power well if we don't need it" policy
-	 * the rest of the driver uses. */
-	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_VGA))
+	 * the rest of the driver uses.
+	 */
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     POWER_DOMAIN_VGA);
+	if (!wakeref)
 		return;
 
 	i915_redisable_vga_power_on(dev_priv);
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_VGA, wakeref);
 }
 
 /* FIXME read out full plane state for all planes */
@@ -15808,12 +15827,13 @@  intel_modeset_setup_hw_state(struct drm_device *dev,
 			     struct drm_modeset_acquire_ctx *ctx)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
-	struct intel_crtc *crtc;
 	struct intel_crtc_state *crtc_state;
 	struct intel_encoder *encoder;
+	struct intel_crtc *crtc;
+	intel_wakeref_t wakeref;
 	int i;
 
-	intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
 
 	intel_early_display_was(dev_priv);
 	intel_modeset_readout_hw_state(dev);
@@ -15883,7 +15903,7 @@  intel_modeset_setup_hw_state(struct drm_device *dev,
 			modeset_put_power_domains(dev_priv, put_domains);
 	}
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
 
 	intel_fbc_init_pipe_state(dev_priv);
 }
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index d3cd40e656fe..fc85fd77a661 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -621,8 +621,8 @@  static void pps_unlock(struct intel_dp *intel_dp)
 
 	mutex_unlock(&dev_priv->pps_mutex);
 
-	intel_display_power_put(dev_priv,
-				intel_aux_power_domain(dp_to_dig_port(intel_dp)));
+	intel_display_power_put_unchecked(dev_priv,
+					  intel_aux_power_domain(dp_to_dig_port(intel_dp)));
 }
 
 static void
@@ -2511,8 +2511,8 @@  static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
 	if ((pp & PANEL_POWER_ON) == 0)
 		intel_dp->panel_power_off_time = ktime_get_boottime();
 
-	intel_display_power_put(dev_priv,
-				intel_aux_power_domain(intel_dig_port));
+	intel_display_power_put_unchecked(dev_priv,
+					  intel_aux_power_domain(intel_dig_port));
 }
 
 static void edp_panel_vdd_work(struct work_struct *__work)
@@ -2657,7 +2657,7 @@  static void edp_panel_off(struct intel_dp *intel_dp)
 	intel_dp->panel_power_off_time = ktime_get_boottime();
 
 	/* We got a reference when we enabled the VDD. */
-	intel_display_power_put(dev_priv, intel_aux_power_domain(dig_port));
+	intel_display_power_put_unchecked(dev_priv, intel_aux_power_domain(dig_port));
 }
 
 void intel_edp_panel_off(struct intel_dp *intel_dp)
@@ -2983,16 +2983,18 @@  static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+	intel_wakeref_t wakeref;
 	bool ret;
 
-	if (!intel_display_power_get_if_enabled(dev_priv,
-						encoder->power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     encoder->power_domain);
+	if (!wakeref)
 		return false;
 
 	ret = intel_dp_port_enabled(dev_priv, intel_dp->output_reg,
 				    encoder->port, pipe);
 
-	intel_display_power_put(dev_priv, encoder->power_domain);
+	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
 
 	return ret;
 }
@@ -5365,12 +5367,13 @@  intel_dp_detect(struct drm_connector *connector,
 	enum drm_connector_status status;
 	enum intel_display_power_domain aux_domain =
 		intel_aux_power_domain(dig_port);
+	intel_wakeref_t wakeref;
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.id, connector->name);
 	WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
 
-	intel_display_power_get(dev_priv, aux_domain);
+	wakeref = intel_display_power_get(dev_priv, aux_domain);
 
 	/* Can't disconnect eDP */
 	if (intel_dp_is_edp(intel_dp))
@@ -5436,7 +5439,7 @@  intel_dp_detect(struct drm_connector *connector,
 
 		ret = intel_dp_retrain_link(encoder, ctx);
 		if (ret) {
-			intel_display_power_put(dev_priv, aux_domain);
+			intel_display_power_put(dev_priv, aux_domain, wakeref);
 			return ret;
 		}
 	}
@@ -5460,7 +5463,7 @@  intel_dp_detect(struct drm_connector *connector,
 	if (status != connector_status_connected && !intel_dp->is_mst)
 		intel_dp_unset_edid(intel_dp);
 
-	intel_display_power_put(dev_priv, aux_domain);
+	intel_display_power_put(dev_priv, aux_domain, wakeref);
 	return status;
 }
 
@@ -5473,6 +5476,7 @@  intel_dp_force(struct drm_connector *connector)
 	struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
 	enum intel_display_power_domain aux_domain =
 		intel_aux_power_domain(dig_port);
+	intel_wakeref_t wakeref;
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.id, connector->name);
@@ -5481,11 +5485,11 @@  intel_dp_force(struct drm_connector *connector)
 	if (connector->status != connector_status_connected)
 		return;
 
-	intel_display_power_get(dev_priv, aux_domain);
+	wakeref = intel_display_power_get(dev_priv, aux_domain);
 
 	intel_dp_set_edid(intel_dp);
 
-	intel_display_power_put(dev_priv, aux_domain);
+	intel_display_power_put(dev_priv, aux_domain, wakeref);
 }
 
 static int intel_dp_get_modes(struct drm_connector *connector)
@@ -5931,6 +5935,7 @@  intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 	struct intel_dp *intel_dp = &intel_dig_port->dp;
 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
 	enum irqreturn ret = IRQ_NONE;
+	intel_wakeref_t wakeref;
 
 	if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
 		/*
@@ -5953,8 +5958,8 @@  intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 		return IRQ_NONE;
 	}
 
-	intel_display_power_get(dev_priv,
-				intel_aux_power_domain(intel_dig_port));
+	wakeref = intel_display_power_get(dev_priv,
+					  intel_aux_power_domain(intel_dig_port));
 
 	if (intel_dp->is_mst) {
 		if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
@@ -5984,7 +5989,8 @@  intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 
 put_power:
 	intel_display_power_put(dev_priv,
-				intel_aux_power_domain(intel_dig_port));
+				intel_aux_power_domain(intel_dig_port),
+				wakeref);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index d513ca875c67..04870e960537 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -345,9 +345,12 @@  static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
 				      struct intel_dpll_hw_state *hw_state)
 {
 	const enum intel_dpll_id id = pll->info->id;
+	intel_wakeref_t wakeref;
 	uint32_t val;
 
-	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     POWER_DOMAIN_PLLS);
+	if (!wakeref)
 		return false;
 
 	val = I915_READ(PCH_DPLL(id));
@@ -355,7 +358,7 @@  static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
 	hw_state->fp0 = I915_READ(PCH_FP0(id));
 	hw_state->fp1 = I915_READ(PCH_FP1(id));
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
 
 	return val & DPLL_VCO_ENABLE;
 }
@@ -509,15 +512,18 @@  static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
 				       struct intel_dpll_hw_state *hw_state)
 {
 	const enum intel_dpll_id id = pll->info->id;
+	intel_wakeref_t wakeref;
 	uint32_t val;
 
-	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     POWER_DOMAIN_PLLS);
+	if (!wakeref)
 		return false;
 
 	val = I915_READ(WRPLL_CTL(id));
 	hw_state->wrpll = val;
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
 
 	return val & WRPLL_PLL_ENABLE;
 }
@@ -526,15 +532,18 @@  static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
 				      struct intel_shared_dpll *pll,
 				      struct intel_dpll_hw_state *hw_state)
 {
+	intel_wakeref_t wakeref;
 	uint32_t val;
 
-	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     POWER_DOMAIN_PLLS);
+	if (!wakeref)
 		return false;
 
 	val = I915_READ(SPLL_CTL);
 	hw_state->spll = val;
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
 
 	return val & SPLL_PLL_ENABLE;
 }
@@ -989,9 +998,12 @@  static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
 	uint32_t val;
 	const struct skl_dpll_regs *regs = skl_dpll_regs;
 	const enum intel_dpll_id id = pll->info->id;
+	intel_wakeref_t wakeref;
 	bool ret;
 
-	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     POWER_DOMAIN_PLLS);
+	if (!wakeref)
 		return false;
 
 	ret = false;
@@ -1011,7 +1023,7 @@  static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
 	ret = true;
 
 out:
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
 
 	return ret;
 }
@@ -1020,12 +1032,15 @@  static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
 				       struct intel_shared_dpll *pll,
 				       struct intel_dpll_hw_state *hw_state)
 {
-	uint32_t val;
 	const struct skl_dpll_regs *regs = skl_dpll_regs;
 	const enum intel_dpll_id id = pll->info->id;
+	intel_wakeref_t wakeref;
+	uint32_t val;
 	bool ret;
 
-	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     POWER_DOMAIN_PLLS);
+	if (!wakeref)
 		return false;
 
 	ret = false;
@@ -1041,7 +1056,7 @@  static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
 	ret = true;
 
 out:
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
 
 	return ret;
 }
@@ -1579,14 +1594,17 @@  static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
 					struct intel_dpll_hw_state *hw_state)
 {
 	enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */
-	uint32_t val;
-	bool ret;
+	intel_wakeref_t wakeref;
 	enum dpio_phy phy;
 	enum dpio_channel ch;
+	uint32_t val;
+	bool ret;
 
 	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
 
-	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     POWER_DOMAIN_PLLS);
+	if (!wakeref)
 		return false;
 
 	ret = false;
@@ -1643,7 +1661,7 @@  static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
 	ret = true;
 
 out:
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
 
 	return ret;
 }
@@ -2091,10 +2109,13 @@  static bool cnl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
 				     struct intel_dpll_hw_state *hw_state)
 {
 	const enum intel_dpll_id id = pll->info->id;
+	intel_wakeref_t wakeref;
 	uint32_t val;
 	bool ret;
 
-	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     POWER_DOMAIN_PLLS);
+	if (!wakeref)
 		return false;
 
 	ret = false;
@@ -2113,7 +2134,7 @@  static bool cnl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
 	ret = true;
 
 out:
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
 
 	return ret;
 }
@@ -2950,11 +2971,14 @@  static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
 				 struct intel_dpll_hw_state *hw_state)
 {
 	const enum intel_dpll_id id = pll->info->id;
-	uint32_t val;
-	enum port port;
+	intel_wakeref_t wakeref;
 	bool ret = false;
+	enum port port;
+	uint32_t val;
 
-	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     POWER_DOMAIN_PLLS);
+	if (!wakeref)
 		return false;
 
 	val = I915_READ(icl_pll_id_to_enable_reg(id));
@@ -3007,7 +3031,7 @@  static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
 
 	ret = true;
 out:
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 93c86b19700e..6fa1e6ff0e28 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -2118,12 +2118,21 @@  bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
 				    enum intel_display_power_domain domain);
 bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
 				      enum intel_display_power_domain domain);
-void intel_display_power_get(struct drm_i915_private *dev_priv,
-			     enum intel_display_power_domain domain);
-bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
+intel_wakeref_t intel_display_power_get(struct drm_i915_private *dev_priv,
 					enum intel_display_power_domain domain);
+intel_wakeref_t
+intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
+				   enum intel_display_power_domain domain);
+void intel_display_power_put_unchecked(struct drm_i915_private *dev_priv,
+				       enum intel_display_power_domain domain);
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
 void intel_display_power_put(struct drm_i915_private *dev_priv,
-			     enum intel_display_power_domain domain);
+			     enum intel_display_power_domain domain,
+			     intel_wakeref_t wakeref);
+#else
+#define intel_display_power_put(i915, domain, wakeref) \
+	intel_display_power_put_unchecked(i915, domain)
+#endif
 void icl_dbuf_slices_update(struct drm_i915_private *dev_priv,
 			    u8 req_slices);
 
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index fc7a09049f81..df3d390e25fe 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -39,6 +39,7 @@  struct intel_dsi {
 	struct intel_encoder base;
 
 	struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS];
+	intel_wakeref_t io_wakeref[I915_MAX_PORTS];
 
 	/* GPIO Desc for CRC based Panel control */
 	struct gpio_desc *gpio_panel;
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 14a0c28fe7c1..14727ac06f67 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1190,15 +1190,17 @@  static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+	intel_wakeref_t wakeref;
 	bool ret;
 
-	if (!intel_display_power_get_if_enabled(dev_priv,
-						encoder->power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     encoder->power_domain);
+	if (!wakeref)
 		return false;
 
 	ret = intel_sdvo_port_enabled(dev_priv, intel_hdmi->hdmi_reg, pipe);
 
-	intel_display_power_put(dev_priv, encoder->power_domain);
+	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
 
 	return ret;
 }
@@ -1895,11 +1897,12 @@  intel_hdmi_set_edid(struct drm_connector *connector)
 {
 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+	intel_wakeref_t wakeref;
 	struct edid *edid;
 	bool connected = false;
 	struct i2c_adapter *i2c;
 
-	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
 	i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
 
@@ -1914,7 +1917,7 @@  intel_hdmi_set_edid(struct drm_connector *connector)
 
 	intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
 
 	to_intel_connector(connector)->detect_edid = edid;
 	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -1939,11 +1942,12 @@  intel_hdmi_detect(struct drm_connector *connector, bool force)
 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 	struct intel_encoder *encoder = &hdmi_to_dig_port(intel_hdmi)->base;
+	intel_wakeref_t wakeref;
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.id, connector->name);
 
-	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
 	if (IS_ICELAKE(dev_priv) &&
 	    !intel_digital_port_connected(encoder))
@@ -1955,7 +1959,7 @@  intel_hdmi_detect(struct drm_connector *connector, bool force)
 		status = connector_status_connected;
 
 out:
-	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
 
 	if (status != connector_status_connected)
 		cec_notifier_phys_addr_invalidate(intel_hdmi->cec_notifier);
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index c6159aff9dc8..4f6dc8c94634 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -697,12 +697,13 @@  do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
 static int
 gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 {
-	struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus,
-					       adapter);
+	struct intel_gmbus *bus =
+		container_of(adapter, struct intel_gmbus, adapter);
 	struct drm_i915_private *dev_priv = bus->dev_priv;
+	intel_wakeref_t wakeref;
 	int ret;
 
-	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
 	if (bus->force_bit) {
 		ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
@@ -714,17 +715,16 @@  gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 			bus->force_bit |= GMBUS_FORCE_BIT_RETRY;
 	}
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
 
 	return ret;
 }
 
 int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
 {
-	struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus,
-					       adapter);
+	struct intel_gmbus *bus =
+		container_of(adapter, struct intel_gmbus, adapter);
 	struct drm_i915_private *dev_priv = bus->dev_priv;
-	int ret;
 	u8 cmd = DRM_HDCP_DDC_AKSV;
 	u8 buf[DRM_HDCP_KSV_LEN] = { 0 };
 	struct i2c_msg msgs[] = {
@@ -741,8 +741,10 @@  int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
 			.buf = buf,
 		}
 	};
+	intel_wakeref_t wakeref;
+	int ret;
 
-	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 	mutex_lock(&dev_priv->gmbus_mutex);
 
 	/*
@@ -753,7 +755,7 @@  int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
 	ret = do_gmbus_xfer(adapter, msgs, ARRAY_SIZE(msgs), GMBUS_AKSV_SELECT);
 
 	mutex_unlock(&dev_priv->gmbus_mutex);
-	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 6adcc8d037bf..b01aacb5d73d 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -94,15 +94,17 @@  static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+	intel_wakeref_t wakeref;
 	bool ret;
 
-	if (!intel_display_power_get_if_enabled(dev_priv,
-						encoder->power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     encoder->power_domain);
+	if (!wakeref)
 		return false;
 
 	ret = intel_lvds_port_enabled(dev_priv, lvds_encoder->reg, pipe);
 
-	intel_display_power_put(dev_priv, encoder->power_domain);
+	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c
index bdabcfab8090..56d614b02302 100644
--- a/drivers/gpu/drm/i915/intel_pipe_crc.c
+++ b/drivers/gpu/drm/i915/intel_pipe_crc.c
@@ -589,6 +589,7 @@  int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
 	struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index];
 	enum intel_display_power_domain power_domain;
 	enum intel_pipe_crc_source source;
+	intel_wakeref_t wakeref;
 	u32 val = 0; /* shut up gcc */
 	int ret = 0;
 
@@ -598,7 +599,8 @@  int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
 	}
 
 	power_domain = POWER_DOMAIN_PIPE(crtc->index);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) {
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref) {
 		DRM_DEBUG_KMS("Trying to capture CRC while pipe is off\n");
 		return -EIO;
 	}
@@ -624,7 +626,7 @@  int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
 	pipe_crc->skipped = 0;
 
 out:
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 83b01cde8113..ab7257720c7e 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3989,10 +3989,12 @@  void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	enum intel_display_power_domain power_domain;
 	enum pipe pipe = crtc->pipe;
+	intel_wakeref_t wakeref;
 	enum plane_id plane_id;
 
 	power_domain = POWER_DOMAIN_PIPE(pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return;
 
 	for_each_plane_id_on_crtc(crtc, plane_id)
@@ -4001,7 +4003,7 @@  void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
 					   &ddb_y[plane_id],
 					   &ddb_uv[plane_id]);
 
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 }
 
 void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index f585ef742efe..fd2fc10dd1e4 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -1867,18 +1867,19 @@  __intel_display_power_get_domain(struct drm_i915_private *dev_priv,
  * Any power domain reference obtained by this function must have a symmetric
  * call to intel_display_power_put() to release the reference again.
  */
-void intel_display_power_get(struct drm_i915_private *dev_priv,
-			     enum intel_display_power_domain domain)
+intel_wakeref_t intel_display_power_get(struct drm_i915_private *dev_priv,
+					enum intel_display_power_domain domain)
 {
 	struct i915_power_domains *power_domains = &dev_priv->power_domains;
-
-	intel_runtime_pm_get(dev_priv);
+	intel_wakeref_t wakeref = intel_runtime_pm_get(dev_priv);
 
 	mutex_lock(&power_domains->lock);
 
 	__intel_display_power_get_domain(dev_priv, domain);
 
 	mutex_unlock(&power_domains->lock);
+
+	return wakeref;
 }
 
 /**
@@ -1893,13 +1894,16 @@  void intel_display_power_get(struct drm_i915_private *dev_priv,
  * Any power domain reference obtained by this function must have a symmetric
  * call to intel_display_power_put() to release the reference again.
  */
-bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
-					enum intel_display_power_domain domain)
+intel_wakeref_t
+intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
+				   enum intel_display_power_domain domain)
 {
 	struct i915_power_domains *power_domains = &dev_priv->power_domains;
+	intel_wakeref_t wakeref;
 	bool is_enabled;
 
-	if (!intel_runtime_pm_get_if_in_use(dev_priv))
+	wakeref = intel_runtime_pm_get_if_in_use(dev_priv);
+	if (!wakeref)
 		return false;
 
 	mutex_lock(&power_domains->lock);
@@ -1913,23 +1917,16 @@  bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
 
 	mutex_unlock(&power_domains->lock);
 
-	if (!is_enabled)
-		intel_runtime_pm_put_unchecked(dev_priv);
+	if (!is_enabled) {
+		intel_runtime_pm_put(dev_priv, wakeref);
+		wakeref = 0;
+	}
 
-	return is_enabled;
+	return wakeref;
 }
 
-/**
- * intel_display_power_put - release a power domain reference
- * @dev_priv: i915 device instance
- * @domain: power domain to reference
- *
- * This function drops the power domain reference obtained by
- * intel_display_power_get() and might power down the corresponding hardware
- * block right away if this is the last reference.
- */
-void intel_display_power_put(struct drm_i915_private *dev_priv,
-			     enum intel_display_power_domain domain)
+static void __intel_display_power_put(struct drm_i915_private *dev_priv,
+				      enum intel_display_power_domain domain)
 {
 	struct i915_power_domains *power_domains;
 	struct i915_power_well *power_well;
@@ -1947,10 +1944,34 @@  void intel_display_power_put(struct drm_i915_private *dev_priv,
 		intel_power_well_put(dev_priv, power_well);
 
 	mutex_unlock(&power_domains->lock);
+}
 
+/**
+ * intel_display_power_put - release a power domain reference
+ * @dev_priv: i915 device instance
+ * @domain: power domain to reference
+ *
+ * This function drops the power domain reference obtained by
+ * intel_display_power_get() and might power down the corresponding hardware
+ * block right away if this is the last reference.
+ */
+void intel_display_power_put_unchecked(struct drm_i915_private *dev_priv,
+				       enum intel_display_power_domain domain)
+{
+	__intel_display_power_put(dev_priv, domain);
 	intel_runtime_pm_put_unchecked(dev_priv);
 }
 
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
+void intel_display_power_put(struct drm_i915_private *dev_priv,
+			     enum intel_display_power_domain domain,
+			     intel_wakeref_t wakeref)
+{
+	__intel_display_power_put(dev_priv, domain);
+	intel_runtime_pm_put(dev_priv, wakeref);
+}
+#endif
+
 #define I830_PIPES_POWER_DOMAINS (		\
 	BIT_ULL(POWER_DOMAIN_PIPE_A) |		\
 	BIT_ULL(POWER_DOMAIN_PIPE_B) |		\
@@ -4060,7 +4081,7 @@  void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv)
 
 	/* Remove the refcount we took to keep power well support disabled. */
 	if (!i915_modparams.disable_power_well)
-		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+		intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
 
 	intel_power_domains_verify_state(dev_priv);
 }
@@ -4079,7 +4100,7 @@  void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv)
  */
 void intel_power_domains_enable(struct drm_i915_private *dev_priv)
 {
-	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+	intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
 
 	intel_power_domains_verify_state(dev_priv);
 }
@@ -4114,7 +4135,7 @@  void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
 {
 	struct i915_power_domains *power_domains = &dev_priv->power_domains;
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+	intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
 
 	/*
 	 * In case of suspend-to-idle (aka S0ix) on a DMC platform without DC9
@@ -4135,7 +4156,7 @@  void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
 	 * power wells if power domains must be deinitialized for suspend.
 	 */
 	if (!i915_modparams.disable_power_well) {
-		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+		intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
 		intel_power_domains_verify_state(dev_priv);
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 8f3982c03925..87a06fcca284 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -618,17 +618,19 @@  skl_plane_get_hw_state(struct intel_plane *plane,
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	enum intel_display_power_domain power_domain;
 	enum plane_id plane_id = plane->id;
+	intel_wakeref_t wakeref;
 	bool ret;
 
 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return false;
 
 	ret = I915_READ(PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE;
 
 	*pipe = plane->pipe;
 
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
@@ -882,17 +884,19 @@  vlv_plane_get_hw_state(struct intel_plane *plane,
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	enum intel_display_power_domain power_domain;
 	enum plane_id plane_id = plane->id;
+	intel_wakeref_t wakeref;
 	bool ret;
 
 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return false;
 
 	ret = I915_READ(SPCNTR(plane->pipe, plane_id)) & SP_ENABLE;
 
 	*pipe = plane->pipe;
 
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
@@ -1051,17 +1055,19 @@  ivb_plane_get_hw_state(struct intel_plane *plane,
 {
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	enum intel_display_power_domain power_domain;
+	intel_wakeref_t wakeref;
 	bool ret;
 
 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return false;
 
 	ret =  I915_READ(SPRCTL(plane->pipe)) & SPRITE_ENABLE;
 
 	*pipe = plane->pipe;
 
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
@@ -1217,17 +1223,19 @@  g4x_plane_get_hw_state(struct intel_plane *plane,
 {
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	enum intel_display_power_domain power_domain;
+	intel_wakeref_t wakeref;
 	bool ret;
 
 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return false;
 
 	ret = I915_READ(DVSCNTR(plane->pipe)) & DVS_ENABLE;
 
 	*pipe = plane->pipe;
 
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_vdsc.c b/drivers/gpu/drm/i915/intel_vdsc.c
index 48537827616f..23abf03736e7 100644
--- a/drivers/gpu/drm/i915/intel_vdsc.c
+++ b/drivers/gpu/drm/i915/intel_vdsc.c
@@ -1082,6 +1082,6 @@  void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state)
 	I915_WRITE(dss_ctl2_reg, dss_ctl2_val);
 
 	/* Disable Power wells for VDSC/joining */
-	intel_display_power_put(dev_priv,
-				intel_dsc_power_domain(old_crtc_state));
+	intel_display_power_put_unchecked(dev_priv,
+					  intel_dsc_power_domain(old_crtc_state));
 }
diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c
index bb1287020f80..d116fead8514 100644
--- a/drivers/gpu/drm/i915/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/vlv_dsi.c
@@ -959,13 +959,15 @@  static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	intel_wakeref_t wakeref;
 	enum port port;
 	bool active = false;
 
 	DRM_DEBUG_KMS("\n");
 
-	if (!intel_display_power_get_if_enabled(dev_priv,
-						encoder->power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv,
+						     encoder->power_domain);
+	if (!wakeref)
 		return false;
 
 	/*
@@ -1021,7 +1023,7 @@  static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
 	}
 
 out_put_power:
-	intel_display_power_put(dev_priv, encoder->power_domain);
+	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
 
 	return active;
 }
@@ -1574,6 +1576,7 @@  vlv_dsi_get_hw_panel_orientation(struct intel_connector *connector)
 	enum drm_panel_orientation orientation;
 	struct intel_plane *plane;
 	struct intel_crtc *crtc;
+	intel_wakeref_t wakeref;
 	enum pipe pipe;
 	u32 val;
 
@@ -1584,7 +1587,8 @@  vlv_dsi_get_hw_panel_orientation(struct intel_connector *connector)
 	plane = to_intel_plane(crtc->base.primary);
 
 	power_domain = POWER_DOMAIN_PIPE(pipe);
-	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
 		return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
 
 	val = I915_READ(DSPCNTR(plane->i9xx_plane));
@@ -1596,7 +1600,7 @@  vlv_dsi_get_hw_panel_orientation(struct intel_connector *connector)
 	else
 		orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
 
-	intel_display_power_put(dev_priv, power_domain);
+	intel_display_power_put(dev_priv, power_domain, wakeref);
 
 	return orientation;
 }

Comments

Chris Wilson <chris@chris-wilson.co.uk> writes:

> The majority of runtime-pm operations are bounded and scoped within a
> function; these are easy to verify that the wakeref are handled
> correctly. We can employ the compiler to help us, and reduce the number
> of wakerefs tracked when debugging, by passing around cookies provided
> by the various rpm_get functions to their rpm_put counterpart. This
> makes the pairing explicit, and given the required wakeref cookie the
> compiler can verify that we pass an initialised value to the rpm_put
> (quite handy for double checking error paths).
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Jani Nikula <jani.nikula@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c     | 35 ++++++------
>  drivers/gpu/drm/i915/i915_drv.h         |  2 +
>  drivers/gpu/drm/i915/i915_gem.c         |  4 +-
>  drivers/gpu/drm/i915/icl_dsi.c          | 36 ++++++++-----
>  drivers/gpu/drm/i915/intel_audio.c      |  3 +-
>  drivers/gpu/drm/i915/intel_cdclk.c      | 10 ++--
>  drivers/gpu/drm/i915/intel_crt.c        | 25 +++++----
>  drivers/gpu/drm/i915/intel_csr.c        | 25 +++++++--
>  drivers/gpu/drm/i915/intel_ddi.c        | 36 ++++++++-----
>  drivers/gpu/drm/i915/intel_display.c    | 68 ++++++++++++++---------
>  drivers/gpu/drm/i915/intel_dp.c         | 38 +++++++------
>  drivers/gpu/drm/i915/intel_dpll_mgr.c   | 66 +++++++++++++++--------
>  drivers/gpu/drm/i915/intel_drv.h        | 17 ++++--
>  drivers/gpu/drm/i915/intel_dsi.h        |  1 +
>  drivers/gpu/drm/i915/intel_hdmi.c       | 18 ++++---
>  drivers/gpu/drm/i915/intel_i2c.c        | 20 +++----
>  drivers/gpu/drm/i915/intel_lvds.c       |  8 +--
>  drivers/gpu/drm/i915/intel_pipe_crc.c   |  6 ++-
>  drivers/gpu/drm/i915/intel_pm.c         |  6 ++-
>  drivers/gpu/drm/i915/intel_runtime_pm.c | 71 ++++++++++++++++---------
>  drivers/gpu/drm/i915/intel_sprite.c     | 24 ++++++---
>  drivers/gpu/drm/i915/intel_vdsc.c       |  4 +-
>  drivers/gpu/drm/i915/vlv_dsi.c          | 14 +++--
>  23 files changed, 347 insertions(+), 190 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 34cbd9a20583..b7dcacf2a5d3 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -626,10 +626,12 @@ static void gen8_display_interrupt_info(struct seq_file *m)
>  
>  	for_each_pipe(dev_priv, pipe) {
>  		enum intel_display_power_domain power_domain;
> +		intel_wakeref_t wakeref;
>  
>  		power_domain = POWER_DOMAIN_PIPE(pipe);
> -		if (!intel_display_power_get_if_enabled(dev_priv,
> -							power_domain)) {
> +		wakeref = intel_display_power_get_if_enabled(dev_priv,
> +							     power_domain);
> +		if (!wakeref) {
>  			seq_printf(m, "Pipe %c power disabled\n",
>  				   pipe_name(pipe));
>  			continue;
> @@ -644,7 +646,7 @@ static void gen8_display_interrupt_info(struct seq_file *m)
>  			   pipe_name(pipe),
>  			   I915_READ(GEN8_DE_PIPE_IER(pipe)));
>  
> -		intel_display_power_put(dev_priv, power_domain);
> +		intel_display_power_put(dev_priv, power_domain, wakeref);
>  	}
>  
>  	seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
> @@ -680,6 +682,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
>  	wakeref = intel_runtime_pm_get(dev_priv);
>  
>  	if (IS_CHERRYVIEW(dev_priv)) {
> +		intel_wakeref_t pref;
> +

In here you are introducing a new, descriptive, power reference for display.
But then you drop it after using it twice. And can't seem to find
reason for inconsistency.

>  		seq_printf(m, "Master Interrupt Control:\t%08x\n",
>  			   I915_READ(GEN8_MASTER_IRQ));
>  
> @@ -695,8 +699,9 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
>  			enum intel_display_power_domain power_domain;
>  
>  			power_domain = POWER_DOMAIN_PIPE(pipe);
> -			if (!intel_display_power_get_if_enabled(dev_priv,
> -								power_domain)) {
> +			pref = intel_display_power_get_if_enabled(dev_priv,
> +								  power_domain);
> +			if (!pref) {
>  				seq_printf(m, "Pipe %c power disabled\n",
>  					   pipe_name(pipe));
>  				continue;
> @@ -706,17 +711,17 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
>  				   pipe_name(pipe),
>  				   I915_READ(PIPESTAT(pipe)));
>  
> -			intel_display_power_put(dev_priv, power_domain);
> +			intel_display_power_put(dev_priv, power_domain, pref);
>  		}
>  
> -		intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
> +		pref = intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
>  		seq_printf(m, "Port hotplug:\t%08x\n",
>  			   I915_READ(PORT_HOTPLUG_EN));
>  		seq_printf(m, "DPFLIPSTAT:\t%08x\n",
>  			   I915_READ(VLV_DPFLIPSTAT));
>  		seq_printf(m, "DPINVGTT:\t%08x\n",
>  			   I915_READ(DPINVGTT));
> -		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
> +		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, pref);
>  
>  		for (i = 0; i < 4; i++) {
>  			seq_printf(m, "GT Interrupt IMR %d:\t%08x\n",
> @@ -779,10 +784,12 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
>  			   I915_READ(VLV_IMR));
>  		for_each_pipe(dev_priv, pipe) {
>  			enum intel_display_power_domain power_domain;
> +			intel_wakeref_t pref;
>  
>  			power_domain = POWER_DOMAIN_PIPE(pipe);
> -			if (!intel_display_power_get_if_enabled(dev_priv,
> -								power_domain)) {
> +			pref = intel_display_power_get_if_enabled(dev_priv,
> +								  power_domain);
> +			if (!pref) {
>  				seq_printf(m, "Pipe %c power disabled\n",
>  					   pipe_name(pipe));
>  				continue;
> @@ -791,7 +798,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
>  			seq_printf(m, "Pipe %c stat:\t%08x\n",
>  				   pipe_name(pipe),
>  				   I915_READ(PIPESTAT(pipe)));
> -			intel_display_power_put(dev_priv, power_domain);
> +			intel_display_power_put(dev_priv, power_domain, pref);
>  		}
>  
>  		seq_printf(m, "Master IER:\t%08x\n",
> @@ -1709,8 +1716,7 @@ static int i915_sr_status(struct seq_file *m, void *unused)
>  	intel_wakeref_t wakeref;
>  	bool sr_enabled = false;
>  
> -	wakeref = intel_runtime_pm_get(dev_priv);
> -	intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
> +	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
>  
>  	if (INTEL_GEN(dev_priv) >= 9)
>  		/* no global SR status; inspect per-plane WM */;
> @@ -1726,8 +1732,7 @@ static int i915_sr_status(struct seq_file *m, void *unused)
>  	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
>  		sr_enabled = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN;
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
> -	intel_runtime_pm_put(dev_priv, wakeref);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
>  
>  	seq_printf(m, "self-refresh: %s\n", enableddisabled(sr_enabled));
>  
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index f0a405604b75..44c1b21febba 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -344,6 +344,7 @@ struct intel_csr {
>  	uint32_t mmiodata[8];
>  	uint32_t dc_state;
>  	uint32_t allowed_dc_mask;
> +	intel_wakeref_t wakeref;
>  };
>  
>  enum i915_cache_level {
> @@ -1982,6 +1983,7 @@ struct drm_i915_private {
>  		 * is a slight delay before we do so.
>  		 */
>  		intel_wakeref_t awake;
> +		intel_wakeref_t power;

This prolly explains the prefs above :)

>  
>  		/**
>  		 * The number of times we have woken up.
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 67fd119bdad8..5ed1c8576525 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -176,7 +176,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
>  	if (INTEL_GEN(i915) >= 6)
>  		gen6_rps_idle(i915);
>  
> -	intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ);
> +	intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ, i915->gt.power);
>  
>  	intel_runtime_pm_put(i915, wakeref);
>  
> @@ -221,7 +221,7 @@ void i915_gem_unpark(struct drm_i915_private *i915)
>  	 * Work around it by grabbing a GT IRQ power domain whilst there is any
>  	 * GT activity, preventing any DC state transitions.
>  	 */
> -	intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
> +	i915->gt.power = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
>  
>  	if (unlikely(++i915->gt.epoch == 0)) /* keep 0 as invalid */
>  		i915->gt.epoch = 1;
> diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c
> index 4dd793b78996..f3a5f03646ce 100644
> --- a/drivers/gpu/drm/i915/icl_dsi.c
> +++ b/drivers/gpu/drm/i915/icl_dsi.c
> @@ -337,9 +337,11 @@ static void gen11_dsi_enable_io_power(struct intel_encoder *encoder)
>  	}
>  
>  	for_each_dsi_port(port, intel_dsi->ports) {
> -		intel_display_power_get(dev_priv, port == PORT_A ?
> -					POWER_DOMAIN_PORT_DDI_A_IO :
> -					POWER_DOMAIN_PORT_DDI_B_IO);
> +		intel_dsi->io_wakeref[port] =
> +			intel_display_power_get(dev_priv,
> +						port == PORT_A ?
> +						POWER_DOMAIN_PORT_DDI_A_IO :
> +						POWER_DOMAIN_PORT_DDI_B_IO);
>  	}
>  }
>  
> @@ -1125,10 +1127,18 @@ static void gen11_dsi_disable_io_power(struct intel_encoder *encoder)
>  	enum port port;
>  	u32 tmp;
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_A_IO);
> -
> -	if (intel_dsi->dual_link)
> -		intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_B_IO);
> +	for_each_dsi_port(port, intel_dsi->ports) {
> +		intel_wakeref_t wakeref;
> +
> +		wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
> +		if (wakeref) {
> +			intel_display_power_put(dev_priv,
> +						port == PORT_A ?
> +						POWER_DOMAIN_PORT_DDI_A_IO :
> +						POWER_DOMAIN_PORT_DDI_B_IO,
> +						wakeref);
> +		}
> +	}

Ok, well. I have been trying to figure out what really is going on here.

First it seems that you fix a bug. We take refs for each dsi port but
only release once special casing 'dual_link' without this patch.

Second, all the hw access is before getting the refs, looking
suspicious.

>  
>  	/* set mode to DDI */
>  	for_each_dsi_port(port, intel_dsi->ports) {
> @@ -1229,13 +1239,15 @@ static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
> -	u32 tmp;
> -	enum port port;
>  	enum transcoder dsi_trans;
> +	intel_wakeref_t wakeref;
> +	enum port port;
>  	bool ret = false;
> +	u32 tmp;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv,
> -						encoder->power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     encoder->power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	for_each_dsi_port(port, intel_dsi->ports) {
> @@ -1260,7 +1272,7 @@ static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder,
>  		ret = tmp & PIPECONF_ENABLE;
>  	}
>  out:
> -	intel_display_power_put(dev_priv, encoder->power_domain);
> +	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
>  	return ret;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
> index 202a58cf2d9f..de26cd0a5497 100644
> --- a/drivers/gpu/drm/i915/intel_audio.c
> +++ b/drivers/gpu/drm/i915/intel_audio.c
> @@ -748,7 +748,8 @@ static void i915_audio_component_get_power(struct device *kdev)
>  
>  static void i915_audio_component_put_power(struct device *kdev)
>  {
> -	intel_display_power_put(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
> +	intel_display_power_put_unchecked(kdev_to_i915(kdev),
> +					  POWER_DOMAIN_AUDIO);
>  }
>  
>  static void i915_audio_component_codec_wake_override(struct device *kdev,
> diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
> index 2021e484a287..73cb7250118e 100644
> --- a/drivers/gpu/drm/i915/intel_cdclk.c
> +++ b/drivers/gpu/drm/i915/intel_cdclk.c
> @@ -520,6 +520,7 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
>  {
>  	int cdclk = cdclk_state->cdclk;
>  	u32 val, cmd = cdclk_state->voltage_level;
> +	intel_wakeref_t wakeref;
>  
>  	switch (cdclk) {
>  	case 400000:
> @@ -539,7 +540,7 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
>  	 * a system suspend.  So grab the PIPE-A domain, which covers
>  	 * the HW blocks needed for the following programming.
>  	 */
> -	intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
> +	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
>  
>  	mutex_lock(&dev_priv->pcu_lock);
>  	val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
> @@ -593,7 +594,7 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
>  
>  	vlv_program_pfi_credits(dev_priv);
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A, wakeref);
>  }
>  
>  static void chv_set_cdclk(struct drm_i915_private *dev_priv,
> @@ -601,6 +602,7 @@ static void chv_set_cdclk(struct drm_i915_private *dev_priv,
>  {
>  	int cdclk = cdclk_state->cdclk;
>  	u32 val, cmd = cdclk_state->voltage_level;
> +	intel_wakeref_t wakeref;
>  
>  	switch (cdclk) {
>  	case 333333:
> @@ -619,7 +621,7 @@ static void chv_set_cdclk(struct drm_i915_private *dev_priv,
>  	 * a system suspend.  So grab the PIPE-A domain, which covers
>  	 * the HW blocks needed for the following programming.
>  	 */
> -	intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
> +	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
>  
>  	mutex_lock(&dev_priv->pcu_lock);
>  	val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
> @@ -637,7 +639,7 @@ static void chv_set_cdclk(struct drm_i915_private *dev_priv,
>  
>  	vlv_program_pfi_credits(dev_priv);
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A, wakeref);
>  }
>  
>  static int bdw_calc_cdclk(int min_cdclk)
> diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
> index 951e9bae6921..33bd2addcbdd 100644
> --- a/drivers/gpu/drm/i915/intel_crt.c
> +++ b/drivers/gpu/drm/i915/intel_crt.c
> @@ -83,15 +83,17 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crt *crt = intel_encoder_to_crt(encoder);
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv,
> -						encoder->power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     encoder->power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = intel_crt_port_enabled(dev_priv, crt->adpa_reg, pipe);
>  
> -	intel_display_power_put(dev_priv, encoder->power_domain);
> +	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -776,6 +778,7 @@ intel_crt_detect(struct drm_connector *connector,
>  	struct drm_i915_private *dev_priv = to_i915(connector->dev);
>  	struct intel_crt *crt = intel_attached_crt(connector);
>  	struct intel_encoder *intel_encoder = &crt->base;
> +	intel_wakeref_t wakeref;
>  	int status, ret;
>  	struct intel_load_detect_pipe tmp;
>  
> @@ -784,7 +787,8 @@ intel_crt_detect(struct drm_connector *connector,
>  		      force);
>  
>  	if (i915_modparams.load_detect_test) {
> -		intel_display_power_get(dev_priv, intel_encoder->power_domain);
> +		wakeref = intel_display_power_get(dev_priv,
> +						  intel_encoder->power_domain);
>  		goto load_detect;
>  	}
>  
> @@ -792,7 +796,8 @@ intel_crt_detect(struct drm_connector *connector,
>  	if (dmi_check_system(intel_spurious_crt_detect))
>  		return connector_status_disconnected;
>  
> -	intel_display_power_get(dev_priv, intel_encoder->power_domain);
> +	wakeref = intel_display_power_get(dev_priv,
> +					  intel_encoder->power_domain);
>  
>  	if (I915_HAS_HOTPLUG(dev_priv)) {
>  		/* We can not rely on the HPD pin always being correctly wired
> @@ -847,7 +852,7 @@ intel_crt_detect(struct drm_connector *connector,
>  	}
>  
>  out:
> -	intel_display_power_put(dev_priv, intel_encoder->power_domain);
> +	intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
>  	return status;
>  }
>  
> @@ -857,10 +862,12 @@ static int intel_crt_get_modes(struct drm_connector *connector)
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	struct intel_crt *crt = intel_attached_crt(connector);
>  	struct intel_encoder *intel_encoder = &crt->base;
> -	int ret;
> +	intel_wakeref_t wakeref;
>  	struct i2c_adapter *i2c;
> +	int ret;
>  
> -	intel_display_power_get(dev_priv, intel_encoder->power_domain);
> +	wakeref = intel_display_power_get(dev_priv,
> +					  intel_encoder->power_domain);
>  
>  	i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
>  	ret = intel_crt_ddc_get_modes(connector, i2c);
> @@ -872,7 +879,7 @@ static int intel_crt_get_modes(struct drm_connector *connector)
>  	ret = intel_crt_ddc_get_modes(connector, i2c);
>  
>  out:
> -	intel_display_power_put(dev_priv, intel_encoder->power_domain);
> +	intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
> index a516697bf57d..ea5fb64d33dd 100644
> --- a/drivers/gpu/drm/i915/intel_csr.c
> +++ b/drivers/gpu/drm/i915/intel_csr.c
> @@ -409,6 +409,21 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
>  	return memcpy(dmc_payload, &fw->data[readcount], nbytes);
>  }
>  
> +static void intel_csr_runtime_pm_get(struct drm_i915_private *dev_priv)
> +{
> +	WARN_ON(dev_priv->csr.wakeref);
> +	dev_priv->csr.wakeref =
> +		intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
> +}
> +
> +static void intel_csr_runtime_pm_put(struct drm_i915_private *dev_priv)
> +{
> +	intel_wakeref_t wakeref __maybe_unused =
> +		fetch_and_zero(&dev_priv->csr.wakeref);
> +
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
> +}
> +
>  static void csr_load_work_fn(struct work_struct *work)
>  {
>  	struct drm_i915_private *dev_priv;
> @@ -424,8 +439,7 @@ static void csr_load_work_fn(struct work_struct *work)
>  
>  	if (dev_priv->csr.dmc_payload) {
>  		intel_csr_load_program(dev_priv);
> -
> -		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
> +		intel_csr_runtime_pm_put(dev_priv);
>  
>  		DRM_INFO("Finished loading DMC firmware %s (v%u.%u)\n",
>  			 dev_priv->csr.fw_path,
> @@ -467,7 +481,7 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv)
>  	 * suspend as runtime suspend *requires* a working CSR for whatever
>  	 * reason.
>  	 */
> -	intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
> +	intel_csr_runtime_pm_get(dev_priv);
>  
>  	if (INTEL_GEN(dev_priv) >= 12) {
>  		/* Allow to load fw via parameter using the last known size */
> @@ -538,7 +552,7 @@ void intel_csr_ucode_suspend(struct drm_i915_private *dev_priv)
>  
>  	/* Drop the reference held in case DMC isn't loaded. */
>  	if (!dev_priv->csr.dmc_payload)
> -		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
> +		intel_csr_runtime_pm_put(dev_priv);
>  }
>  
>  /**
> @@ -558,7 +572,7 @@ void intel_csr_ucode_resume(struct drm_i915_private *dev_priv)
>  	 * loaded.
>  	 */
>  	if (!dev_priv->csr.dmc_payload)
> -		intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
> +		intel_csr_runtime_pm_get(dev_priv);
>  }
>  
>  /**
> @@ -574,6 +588,7 @@ void intel_csr_ucode_fini(struct drm_i915_private *dev_priv)
>  		return;
>  
>  	intel_csr_ucode_suspend(dev_priv);
> +	WARN_ON(dev_priv->csr.wakeref);
>  
>  	kfree(dev_priv->csr.dmc_payload);
>  }
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 2d6ed990a232..7f3cd055de50 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1860,12 +1860,14 @@ int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
>  {
>  	struct drm_device *dev = intel_encoder->base.dev;
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> +	intel_wakeref_t wakeref;
>  	enum pipe pipe = 0;
>  	int ret = 0;
>  	uint32_t tmp;
>  
> -	if (WARN_ON(!intel_display_power_get_if_enabled(dev_priv,
> -						intel_encoder->power_domain)))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     intel_encoder->power_domain);
> +	if (WARN_ON(!wakeref))
>  		return -ENXIO;
>  
>  	if (WARN_ON(!intel_encoder->get_hw_state(intel_encoder, &pipe))) {
> @@ -1880,7 +1882,7 @@ int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
>  		tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
>  	I915_WRITE(TRANS_DDI_FUNC_CTL(pipe), tmp);
>  out:
> -	intel_display_power_put(dev_priv, intel_encoder->power_domain);
> +	intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
>  	return ret;
>  }
>  
> @@ -1891,13 +1893,15 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
>  	struct intel_encoder *encoder = intel_connector->encoder;
>  	int type = intel_connector->base.connector_type;
>  	enum port port = encoder->port;
> -	enum pipe pipe = 0;
>  	enum transcoder cpu_transcoder;
> +	intel_wakeref_t wakeref;
> +	enum pipe pipe = 0;
>  	uint32_t tmp;
>  	bool ret;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv,
> -						encoder->power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     encoder->power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	if (!encoder->get_hw_state(encoder, &pipe)) {
> @@ -1939,7 +1943,7 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
>  	}
>  
>  out:
> -	intel_display_power_put(dev_priv, encoder->power_domain);
> +	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -1950,6 +1954,7 @@ static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
>  	struct drm_device *dev = encoder->base.dev;
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	enum port port = encoder->port;
> +	intel_wakeref_t wakeref;
>  	enum pipe p;
>  	u32 tmp;
>  	u8 mst_pipe_mask;
> @@ -1957,8 +1962,9 @@ static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
>  	*pipe_mask = 0;
>  	*is_dp_mst = false;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv,
> -						encoder->power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     encoder->power_domain);
> +	if (!wakeref)
>  		return;
>  
>  	tmp = I915_READ(DDI_BUF_CTL(port));
> @@ -2029,7 +2035,7 @@ static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
>  				  "(PHY_CTL %08x)\n", port_name(port), tmp);
>  	}
>  
> -	intel_display_power_put(dev_priv, encoder->power_domain);
> +	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
>  }
>  
>  bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
> @@ -3286,7 +3292,8 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
>  	intel_edp_panel_vdd_on(intel_dp);
>  	intel_edp_panel_off(intel_dp);
>  
> -	intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain);
> +	intel_display_power_put_unchecked(dev_priv,
> +					  dig_port->ddi_io_power_domain);
>  
>  	intel_ddi_clk_disable(encoder);
>  }
> @@ -3306,7 +3313,8 @@ static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
>  
>  	intel_disable_ddi_buf(encoder, old_crtc_state);
>  
> -	intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain);
> +	intel_display_power_put_unchecked(dev_priv,
> +					  dig_port->ddi_io_power_domain);
>  
>  	intel_ddi_clk_disable(encoder);
>  
> @@ -3626,8 +3634,8 @@ intel_ddi_post_pll_disable(struct intel_encoder *encoder,
>  
>  	if (intel_crtc_has_dp_encoder(crtc_state) ||
>  	    intel_port_is_tc(dev_priv, encoder->port))
> -		intel_display_power_put(dev_priv,
> -					intel_ddi_main_link_aux_domain(dig_port));
> +		intel_display_power_put_unchecked(dev_priv,
> +						  intel_ddi_main_link_aux_domain(dig_port));
>  }
>  
>  void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index b0b8f9ffd873..36c56d1637b8 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -1197,17 +1197,19 @@ void assert_pipe(struct drm_i915_private *dev_priv,
>  	enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
>  								      pipe);
>  	enum intel_display_power_domain power_domain;
> +	intel_wakeref_t wakeref;
>  
>  	/* we keep both pipes enabled on 830 */
>  	if (IS_I830(dev_priv))
>  		state = true;
>  
>  	power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
> -	if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (wakeref) {
>  		u32 val = I915_READ(PIPECONF(cpu_transcoder));
>  		cur_state = !!(val & PIPECONF_ENABLE);
>  
> -		intel_display_power_put(dev_priv, power_domain);
> +		intel_display_power_put(dev_priv, power_domain, wakeref);
>  	} else {
>  		cur_state = false;
>  	}
> @@ -3412,6 +3414,7 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
>  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	enum intel_display_power_domain power_domain;
>  	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  	u32 val;
>  
> @@ -3421,7 +3424,8 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
>  	 * display power wells.
>  	 */
>  	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	val = I915_READ(DSPCNTR(i9xx_plane));
> @@ -3434,7 +3438,7 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
>  		*pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
>  			DISPPLANE_SEL_PIPE_SHIFT;
>  
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -6107,7 +6111,7 @@ static void modeset_put_power_domains(struct drm_i915_private *dev_priv,
>  	enum intel_display_power_domain domain;
>  
>  	for_each_power_domain(domain, domains)
> -		intel_display_power_put(dev_priv, domain);
> +		intel_display_power_put_unchecked(dev_priv, domain);
>  }
>  
>  static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
> @@ -6354,7 +6358,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc,
>  
>  	domains = intel_crtc->enabled_power_domains;
>  	for_each_power_domain(domain, domains)
> -		intel_display_power_put(dev_priv, domain);
> +		intel_display_power_put_unchecked(dev_priv, domain);
>  	intel_crtc->enabled_power_domains = 0;
>  
>  	dev_priv->active_crtcs &= ~(1 << intel_crtc->pipe);
> @@ -7966,11 +7970,13 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
>  	enum intel_display_power_domain power_domain;
> +	intel_wakeref_t wakeref;
>  	uint32_t tmp;
>  	bool ret;
>  
>  	power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
> @@ -8071,7 +8077,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
>  	ret = true;
>  
>  out:
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -9038,11 +9044,13 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
>  	struct drm_device *dev = crtc->base.dev;
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	enum intel_display_power_domain power_domain;
> +	intel_wakeref_t wakeref;
>  	uint32_t tmp;
>  	bool ret;
>  
>  	power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
> @@ -9125,7 +9133,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
>  	ret = true;
>  
>  out:
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -9734,7 +9742,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
>  
>  out:
>  	for_each_power_domain(power_domain, power_domain_mask)
> -		intel_display_power_put(dev_priv, power_domain);
> +		intel_display_power_put_unchecked(dev_priv, power_domain);
>  
>  	return active;
>  }
> @@ -9984,17 +9992,19 @@ static bool i845_cursor_get_hw_state(struct intel_plane *plane,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	enum intel_display_power_domain power_domain;
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
>  	power_domain = POWER_DOMAIN_PIPE(PIPE_A);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE;
>  
>  	*pipe = PIPE_A;
>  
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -10217,6 +10227,7 @@ static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	enum intel_display_power_domain power_domain;
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  	u32 val;
>  
> @@ -10226,7 +10237,8 @@ static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
>  	 * display power wells.
>  	 */
>  	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	val = I915_READ(CURCNTR(plane->pipe));
> @@ -10239,7 +10251,7 @@ static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
>  		*pipe = (val & MCURSOR_PIPE_SELECT_MASK) >>
>  			MCURSOR_PIPE_SELECT_SHIFT;
>  
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -12950,6 +12962,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
>  	struct drm_crtc *crtc;
>  	struct intel_crtc *intel_crtc;
>  	u64 put_domains[I915_MAX_PIPES] = {};
> +	intel_wakeref_t wakeref = 0;
>  	int i;
>  
>  	intel_atomic_commit_fence_wait(intel_state);
> @@ -12957,7 +12970,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
>  	drm_atomic_helper_wait_for_dependencies(state);
>  
>  	if (intel_state->modeset)
> -		intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
> +		wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
>  
>  	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
>  		old_intel_crtc_state = to_intel_crtc_state(old_crtc_state);
> @@ -13094,7 +13107,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
>  		 * the culprit.
>  		 */
>  		intel_uncore_arm_unclaimed_mmio_detection(dev_priv);
> -		intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
> +		intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET, wakeref);
>  	}
>  
>  	/*
> @@ -15496,19 +15509,25 @@ void i915_redisable_vga_power_on(struct drm_i915_private *dev_priv)
>  
>  void i915_redisable_vga(struct drm_i915_private *dev_priv)
>  {
> -	/* This function can be called both from intel_modeset_setup_hw_state or
> +	intel_wakeref_t wakeref;
> +
> +	/*
> +	 * This function can be called both from intel_modeset_setup_hw_state or
>  	 * at a very early point in our resume sequence, where the power well
>  	 * structures are not yet restored. Since this function is at a very
>  	 * paranoid "someone might have enabled VGA while we were not looking"
>  	 * level, just check if the power well is enabled instead of trying to
>  	 * follow the "don't touch the power well if we don't need it" policy
> -	 * the rest of the driver uses. */
> -	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_VGA))
> +	 * the rest of the driver uses.
> +	 */
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     POWER_DOMAIN_VGA);
> +	if (!wakeref)
>  		return;
>  
>  	i915_redisable_vga_power_on(dev_priv);
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_VGA, wakeref);
>  }
>  
>  /* FIXME read out full plane state for all planes */
> @@ -15808,12 +15827,13 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
>  			     struct drm_modeset_acquire_ctx *ctx)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> -	struct intel_crtc *crtc;
>  	struct intel_crtc_state *crtc_state;
>  	struct intel_encoder *encoder;
> +	struct intel_crtc *crtc;

Not that I mind but I don't understand the reasoning
behind the change of order on this and on few other places in this
patch.


> +	intel_wakeref_t wakeref;
>  	int i;
>  
> -	intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
> +	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
>  
>  	intel_early_display_was(dev_priv);
>  	intel_modeset_readout_hw_state(dev);
> @@ -15883,7 +15903,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
>  			modeset_put_power_domains(dev_priv, put_domains);
>  	}
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
>  
>  	intel_fbc_init_pipe_state(dev_priv);
>  }
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index d3cd40e656fe..fc85fd77a661 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -621,8 +621,8 @@ static void pps_unlock(struct intel_dp *intel_dp)
>  
>  	mutex_unlock(&dev_priv->pps_mutex);
>  
> -	intel_display_power_put(dev_priv,
> -				intel_aux_power_domain(dp_to_dig_port(intel_dp)));
> +	intel_display_power_put_unchecked(dev_priv,
> +					  intel_aux_power_domain(dp_to_dig_port(intel_dp)));
>  }
>  
>  static void
> @@ -2511,8 +2511,8 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
>  	if ((pp & PANEL_POWER_ON) == 0)
>  		intel_dp->panel_power_off_time = ktime_get_boottime();
>  
> -	intel_display_power_put(dev_priv,
> -				intel_aux_power_domain(intel_dig_port));
> +	intel_display_power_put_unchecked(dev_priv,
> +					  intel_aux_power_domain(intel_dig_port));
>  }
>  
>  static void edp_panel_vdd_work(struct work_struct *__work)
> @@ -2657,7 +2657,7 @@ static void edp_panel_off(struct intel_dp *intel_dp)
>  	intel_dp->panel_power_off_time = ktime_get_boottime();
>  
>  	/* We got a reference when we enabled the VDD. */
> -	intel_display_power_put(dev_priv, intel_aux_power_domain(dig_port));
> +	intel_display_power_put_unchecked(dev_priv, intel_aux_power_domain(dig_port));
>  }
>  
>  void intel_edp_panel_off(struct intel_dp *intel_dp)
> @@ -2983,16 +2983,18 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv,
> -						encoder->power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     encoder->power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = intel_dp_port_enabled(dev_priv, intel_dp->output_reg,
>  				    encoder->port, pipe);
>  
> -	intel_display_power_put(dev_priv, encoder->power_domain);
> +	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -5365,12 +5367,13 @@ intel_dp_detect(struct drm_connector *connector,
>  	enum drm_connector_status status;
>  	enum intel_display_power_domain aux_domain =
>  		intel_aux_power_domain(dig_port);
> +	intel_wakeref_t wakeref;
>  
>  	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
>  		      connector->base.id, connector->name);
>  	WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
>  
> -	intel_display_power_get(dev_priv, aux_domain);
> +	wakeref = intel_display_power_get(dev_priv, aux_domain);
>  
>  	/* Can't disconnect eDP */
>  	if (intel_dp_is_edp(intel_dp))
> @@ -5436,7 +5439,7 @@ intel_dp_detect(struct drm_connector *connector,
>  
>  		ret = intel_dp_retrain_link(encoder, ctx);
>  		if (ret) {
> -			intel_display_power_put(dev_priv, aux_domain);
> +			intel_display_power_put(dev_priv, aux_domain, wakeref);
>  			return ret;
>  		}
>  	}
> @@ -5460,7 +5463,7 @@ intel_dp_detect(struct drm_connector *connector,
>  	if (status != connector_status_connected && !intel_dp->is_mst)
>  		intel_dp_unset_edid(intel_dp);
>  
> -	intel_display_power_put(dev_priv, aux_domain);
> +	intel_display_power_put(dev_priv, aux_domain, wakeref);
>  	return status;
>  }
>  
> @@ -5473,6 +5476,7 @@ intel_dp_force(struct drm_connector *connector)
>  	struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
>  	enum intel_display_power_domain aux_domain =
>  		intel_aux_power_domain(dig_port);
> +	intel_wakeref_t wakeref;
>  
>  	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
>  		      connector->base.id, connector->name);
> @@ -5481,11 +5485,11 @@ intel_dp_force(struct drm_connector *connector)
>  	if (connector->status != connector_status_connected)
>  		return;
>  
> -	intel_display_power_get(dev_priv, aux_domain);
> +	wakeref = intel_display_power_get(dev_priv, aux_domain);
>  
>  	intel_dp_set_edid(intel_dp);
>  
> -	intel_display_power_put(dev_priv, aux_domain);
> +	intel_display_power_put(dev_priv, aux_domain, wakeref);
>  }
>  
>  static int intel_dp_get_modes(struct drm_connector *connector)
> @@ -5931,6 +5935,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
>  	struct intel_dp *intel_dp = &intel_dig_port->dp;
>  	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
>  	enum irqreturn ret = IRQ_NONE;
> +	intel_wakeref_t wakeref;
>  
>  	if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
>  		/*
> @@ -5953,8 +5958,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
>  		return IRQ_NONE;
>  	}
>  
> -	intel_display_power_get(dev_priv,
> -				intel_aux_power_domain(intel_dig_port));
> +	wakeref = intel_display_power_get(dev_priv,
> +					  intel_aux_power_domain(intel_dig_port));
>  
>  	if (intel_dp->is_mst) {
>  		if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
> @@ -5984,7 +5989,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
>  
>  put_power:
>  	intel_display_power_put(dev_priv,
> -				intel_aux_power_domain(intel_dig_port));
> +				intel_aux_power_domain(intel_dig_port),
> +				wakeref);
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> index d513ca875c67..04870e960537 100644
> --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> @@ -345,9 +345,12 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
>  				      struct intel_dpll_hw_state *hw_state)
>  {
>  	const enum intel_dpll_id id = pll->info->id;
> +	intel_wakeref_t wakeref;
>  	uint32_t val;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     POWER_DOMAIN_PLLS);
> +	if (!wakeref)
>  		return false;
>  
>  	val = I915_READ(PCH_DPLL(id));
> @@ -355,7 +358,7 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
>  	hw_state->fp0 = I915_READ(PCH_FP0(id));
>  	hw_state->fp1 = I915_READ(PCH_FP1(id));
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
>  
>  	return val & DPLL_VCO_ENABLE;
>  }
> @@ -509,15 +512,18 @@ static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
>  				       struct intel_dpll_hw_state *hw_state)
>  {
>  	const enum intel_dpll_id id = pll->info->id;
> +	intel_wakeref_t wakeref;
>  	uint32_t val;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     POWER_DOMAIN_PLLS);
> +	if (!wakeref)
>  		return false;
>  
>  	val = I915_READ(WRPLL_CTL(id));
>  	hw_state->wrpll = val;
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
>  
>  	return val & WRPLL_PLL_ENABLE;
>  }
> @@ -526,15 +532,18 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
>  				      struct intel_shared_dpll *pll,
>  				      struct intel_dpll_hw_state *hw_state)
>  {
> +	intel_wakeref_t wakeref;
>  	uint32_t val;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     POWER_DOMAIN_PLLS);
> +	if (!wakeref)
>  		return false;
>  
>  	val = I915_READ(SPLL_CTL);
>  	hw_state->spll = val;
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
>  
>  	return val & SPLL_PLL_ENABLE;
>  }
> @@ -989,9 +998,12 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
>  	uint32_t val;
>  	const struct skl_dpll_regs *regs = skl_dpll_regs;
>  	const enum intel_dpll_id id = pll->info->id;
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     POWER_DOMAIN_PLLS);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = false;
> @@ -1011,7 +1023,7 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
>  	ret = true;
>  
>  out:
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
>  
>  	return ret;
>  }
> @@ -1020,12 +1032,15 @@ static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
>  				       struct intel_shared_dpll *pll,
>  				       struct intel_dpll_hw_state *hw_state)
>  {
> -	uint32_t val;
>  	const struct skl_dpll_regs *regs = skl_dpll_regs;
>  	const enum intel_dpll_id id = pll->info->id;
> +	intel_wakeref_t wakeref;
> +	uint32_t val;
>  	bool ret;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     POWER_DOMAIN_PLLS);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = false;
> @@ -1041,7 +1056,7 @@ static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
>  	ret = true;
>  
>  out:
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
>  
>  	return ret;
>  }
> @@ -1579,14 +1594,17 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
>  					struct intel_dpll_hw_state *hw_state)
>  {
>  	enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */
> -	uint32_t val;
> -	bool ret;
> +	intel_wakeref_t wakeref;
>  	enum dpio_phy phy;
>  	enum dpio_channel ch;
> +	uint32_t val;
> +	bool ret;
>  
>  	bxt_port_to_phy_channel(dev_priv, port, &phy, &ch);
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     POWER_DOMAIN_PLLS);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = false;
> @@ -1643,7 +1661,7 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
>  	ret = true;
>  
>  out:
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
>  
>  	return ret;
>  }
> @@ -2091,10 +2109,13 @@ static bool cnl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
>  				     struct intel_dpll_hw_state *hw_state)
>  {
>  	const enum intel_dpll_id id = pll->info->id;
> +	intel_wakeref_t wakeref;
>  	uint32_t val;
>  	bool ret;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     POWER_DOMAIN_PLLS);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = false;
> @@ -2113,7 +2134,7 @@ static bool cnl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
>  	ret = true;
>  
>  out:
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
>  
>  	return ret;
>  }
> @@ -2950,11 +2971,14 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
>  				 struct intel_dpll_hw_state *hw_state)
>  {
>  	const enum intel_dpll_id id = pll->info->id;
> -	uint32_t val;
> -	enum port port;
> +	intel_wakeref_t wakeref;
>  	bool ret = false;
> +	enum port port;
> +	uint32_t val;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     POWER_DOMAIN_PLLS);
> +	if (!wakeref)
>  		return false;
>  
>  	val = I915_READ(icl_pll_id_to_enable_reg(id));
> @@ -3007,7 +3031,7 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
>  
>  	ret = true;
>  out:
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS, wakeref);
>  	return ret;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 93c86b19700e..6fa1e6ff0e28 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -2118,12 +2118,21 @@ bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
>  				    enum intel_display_power_domain domain);
>  bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
>  				      enum intel_display_power_domain domain);
> -void intel_display_power_get(struct drm_i915_private *dev_priv,
> -			     enum intel_display_power_domain domain);
> -bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
> +intel_wakeref_t intel_display_power_get(struct drm_i915_private *dev_priv,
>  					enum intel_display_power_domain domain);
> +intel_wakeref_t
> +intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
> +				   enum intel_display_power_domain domain);
> +void intel_display_power_put_unchecked(struct drm_i915_private *dev_priv,
> +				       enum intel_display_power_domain domain);
> +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
>  void intel_display_power_put(struct drm_i915_private *dev_priv,
> -			     enum intel_display_power_domain domain);
> +			     enum intel_display_power_domain domain,
> +			     intel_wakeref_t wakeref);
> +#else
> +#define intel_display_power_put(i915, domain, wakeref) \
> +	intel_display_power_put_unchecked(i915, domain)
> +#endif
>  void icl_dbuf_slices_update(struct drm_i915_private *dev_priv,
>  			    u8 req_slices);
>  
> diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
> index fc7a09049f81..df3d390e25fe 100644
> --- a/drivers/gpu/drm/i915/intel_dsi.h
> +++ b/drivers/gpu/drm/i915/intel_dsi.h
> @@ -39,6 +39,7 @@ struct intel_dsi {
>  	struct intel_encoder base;
>  
>  	struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS];
> +	intel_wakeref_t io_wakeref[I915_MAX_PORTS];
>  
>  	/* GPIO Desc for CRC based Panel control */
>  	struct gpio_desc *gpio_panel;
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index 14a0c28fe7c1..14727ac06f67 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -1190,15 +1190,17 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv,
> -						encoder->power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     encoder->power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = intel_sdvo_port_enabled(dev_priv, intel_hdmi->hdmi_reg, pipe);
>  
> -	intel_display_power_put(dev_priv, encoder->power_domain);
> +	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -1895,11 +1897,12 @@ intel_hdmi_set_edid(struct drm_connector *connector)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(connector->dev);
>  	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
> +	intel_wakeref_t wakeref;
>  	struct edid *edid;
>  	bool connected = false;
>  	struct i2c_adapter *i2c;
>  
> -	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
> +	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
>  
>  	i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
>  
> @@ -1914,7 +1917,7 @@ intel_hdmi_set_edid(struct drm_connector *connector)
>  
>  	intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
>  
>  	to_intel_connector(connector)->detect_edid = edid;
>  	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
> @@ -1939,11 +1942,12 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
>  	struct drm_i915_private *dev_priv = to_i915(connector->dev);
>  	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
>  	struct intel_encoder *encoder = &hdmi_to_dig_port(intel_hdmi)->base;
> +	intel_wakeref_t wakeref;
>  
>  	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
>  		      connector->base.id, connector->name);
>  
> -	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
> +	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
>  
>  	if (IS_ICELAKE(dev_priv) &&
>  	    !intel_digital_port_connected(encoder))
> @@ -1955,7 +1959,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
>  		status = connector_status_connected;
>  
>  out:
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
>  
>  	if (status != connector_status_connected)
>  		cec_notifier_phys_addr_invalidate(intel_hdmi->cec_notifier);
> diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
> index c6159aff9dc8..4f6dc8c94634 100644
> --- a/drivers/gpu/drm/i915/intel_i2c.c
> +++ b/drivers/gpu/drm/i915/intel_i2c.c
> @@ -697,12 +697,13 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
>  static int
>  gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
>  {
> -	struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus,
> -					       adapter);
> +	struct intel_gmbus *bus =
> +		container_of(adapter, struct intel_gmbus, adapter);
>  	struct drm_i915_private *dev_priv = bus->dev_priv;
> +	intel_wakeref_t wakeref;
>  	int ret;
>  
> -	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
> +	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
>  
>  	if (bus->force_bit) {
>  		ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
> @@ -714,17 +715,16 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
>  			bus->force_bit |= GMBUS_FORCE_BIT_RETRY;
>  	}
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
>  
>  	return ret;
>  }
>  
>  int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
>  {
> -	struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus,
> -					       adapter);
> +	struct intel_gmbus *bus =
> +		container_of(adapter, struct intel_gmbus, adapter);
>  	struct drm_i915_private *dev_priv = bus->dev_priv;
> -	int ret;
>  	u8 cmd = DRM_HDCP_DDC_AKSV;
>  	u8 buf[DRM_HDCP_KSV_LEN] = { 0 };
>  	struct i2c_msg msgs[] = {
> @@ -741,8 +741,10 @@ int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
>  			.buf = buf,
>  		}
>  	};
> +	intel_wakeref_t wakeref;
> +	int ret;
>  
> -	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
> +	wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
>  	mutex_lock(&dev_priv->gmbus_mutex);
>  
>  	/*
> @@ -753,7 +755,7 @@ int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
>  	ret = do_gmbus_xfer(adapter, msgs, ARRAY_SIZE(msgs), GMBUS_AKSV_SELECT);
>  
>  	mutex_unlock(&dev_priv->gmbus_mutex);
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
> +	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
> index 6adcc8d037bf..b01aacb5d73d 100644
> --- a/drivers/gpu/drm/i915/intel_lvds.c
> +++ b/drivers/gpu/drm/i915/intel_lvds.c
> @@ -94,15 +94,17 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv,
> -						encoder->power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     encoder->power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = intel_lvds_port_enabled(dev_priv, lvds_encoder->reg, pipe);
>  
> -	intel_display_power_put(dev_priv, encoder->power_domain);
> +	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c
> index bdabcfab8090..56d614b02302 100644
> --- a/drivers/gpu/drm/i915/intel_pipe_crc.c
> +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c
> @@ -589,6 +589,7 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
>  	struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index];
>  	enum intel_display_power_domain power_domain;
>  	enum intel_pipe_crc_source source;
> +	intel_wakeref_t wakeref;
>  	u32 val = 0; /* shut up gcc */
>  	int ret = 0;
>  
> @@ -598,7 +599,8 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
>  	}
>  
>  	power_domain = POWER_DOMAIN_PIPE(crtc->index);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) {
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref) {
>  		DRM_DEBUG_KMS("Trying to capture CRC while pipe is off\n");
>  		return -EIO;
>  	}
> @@ -624,7 +626,7 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
>  	pipe_crc->skipped = 0;
>  
>  out:
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 83b01cde8113..ab7257720c7e 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3989,10 +3989,12 @@ void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
>  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
>  	enum intel_display_power_domain power_domain;
>  	enum pipe pipe = crtc->pipe;
> +	intel_wakeref_t wakeref;
>  	enum plane_id plane_id;
>  
>  	power_domain = POWER_DOMAIN_PIPE(pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return;
>  
>  	for_each_plane_id_on_crtc(crtc, plane_id)
> @@ -4001,7 +4003,7 @@ void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
>  					   &ddb_y[plane_id],
>  					   &ddb_uv[plane_id]);
>  
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  }
>  
>  void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> index f585ef742efe..fd2fc10dd1e4 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -1867,18 +1867,19 @@ __intel_display_power_get_domain(struct drm_i915_private *dev_priv,
>   * Any power domain reference obtained by this function must have a symmetric
>   * call to intel_display_power_put() to release the reference again.
>   */
> -void intel_display_power_get(struct drm_i915_private *dev_priv,
> -			     enum intel_display_power_domain domain)
> +intel_wakeref_t intel_display_power_get(struct drm_i915_private *dev_priv,
> +					enum intel_display_power_domain domain)
>  {
>  	struct i915_power_domains *power_domains = &dev_priv->power_domains;
> -
> -	intel_runtime_pm_get(dev_priv);
> +	intel_wakeref_t wakeref = intel_runtime_pm_get(dev_priv);
>  
>  	mutex_lock(&power_domains->lock);
>  
>  	__intel_display_power_get_domain(dev_priv, domain);
>  
>  	mutex_unlock(&power_domains->lock);
> +
> +	return wakeref;
>  }
>  
>  /**
> @@ -1893,13 +1894,16 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
>   * Any power domain reference obtained by this function must have a symmetric
>   * call to intel_display_power_put() to release the reference again.
>   */
> -bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
> -					enum intel_display_power_domain domain)
> +intel_wakeref_t
> +intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
> +				   enum intel_display_power_domain domain)
>  {
>  	struct i915_power_domains *power_domains = &dev_priv->power_domains;
> +	intel_wakeref_t wakeref;
>  	bool is_enabled;
>  
> -	if (!intel_runtime_pm_get_if_in_use(dev_priv))
> +	wakeref = intel_runtime_pm_get_if_in_use(dev_priv);
> +	if (!wakeref)
>  		return false;
>  
>  	mutex_lock(&power_domains->lock);
> @@ -1913,23 +1917,16 @@ bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
>  
>  	mutex_unlock(&power_domains->lock);
>  
> -	if (!is_enabled)
> -		intel_runtime_pm_put_unchecked(dev_priv);
> +	if (!is_enabled) {
> +		intel_runtime_pm_put(dev_priv, wakeref);
> +		wakeref = 0;
> +	}
>  
> -	return is_enabled;
> +	return wakeref;
>  }
>  
> -/**
> - * intel_display_power_put - release a power domain reference
> - * @dev_priv: i915 device instance
> - * @domain: power domain to reference
> - *
> - * This function drops the power domain reference obtained by
> - * intel_display_power_get() and might power down the corresponding hardware
> - * block right away if this is the last reference.
> - */
> -void intel_display_power_put(struct drm_i915_private *dev_priv,
> -			     enum intel_display_power_domain domain)
> +static void __intel_display_power_put(struct drm_i915_private *dev_priv,
> +				      enum intel_display_power_domain domain)
>  {
>  	struct i915_power_domains *power_domains;
>  	struct i915_power_well *power_well;
> @@ -1947,10 +1944,34 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
>  		intel_power_well_put(dev_priv, power_well);
>  
>  	mutex_unlock(&power_domains->lock);
> +}
>  
> +/**
> + * intel_display_power_put - release a power domain reference

+unchecked? or is this in wrong place.

And the perf oa_config unrelated changes are gone. Good.
-Mika

> + * @dev_priv: i915 device instance
> + * @domain: power domain to reference
> + *
> + * This function drops the power domain reference obtained by
> + * intel_display_power_get() and might power down the corresponding hardware
> + * block right away if this is the last reference.
> + */
> +void intel_display_power_put_unchecked(struct drm_i915_private *dev_priv,
> +				       enum intel_display_power_domain domain)
> +{
> +	__intel_display_power_put(dev_priv, domain);
>  	intel_runtime_pm_put_unchecked(dev_priv);
>  }
>  
> +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
> +void intel_display_power_put(struct drm_i915_private *dev_priv,
> +			     enum intel_display_power_domain domain,
> +			     intel_wakeref_t wakeref)
> +{
> +	__intel_display_power_put(dev_priv, domain);
> +	intel_runtime_pm_put(dev_priv, wakeref);
> +}
> +#endif
> +
>  #define I830_PIPES_POWER_DOMAINS (		\
>  	BIT_ULL(POWER_DOMAIN_PIPE_A) |		\
>  	BIT_ULL(POWER_DOMAIN_PIPE_B) |		\
> @@ -4060,7 +4081,7 @@ void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv)
>  
>  	/* Remove the refcount we took to keep power well support disabled. */
>  	if (!i915_modparams.disable_power_well)
> -		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
> +		intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
>  
>  	intel_power_domains_verify_state(dev_priv);
>  }
> @@ -4079,7 +4100,7 @@ void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv)
>   */
>  void intel_power_domains_enable(struct drm_i915_private *dev_priv)
>  {
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
> +	intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
>  
>  	intel_power_domains_verify_state(dev_priv);
>  }
> @@ -4114,7 +4135,7 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
>  {
>  	struct i915_power_domains *power_domains = &dev_priv->power_domains;
>  
> -	intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
> +	intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
>  
>  	/*
>  	 * In case of suspend-to-idle (aka S0ix) on a DMC platform without DC9
> @@ -4135,7 +4156,7 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
>  	 * power wells if power domains must be deinitialized for suspend.
>  	 */
>  	if (!i915_modparams.disable_power_well) {
> -		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
> +		intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
>  		intel_power_domains_verify_state(dev_priv);
>  	}
>  
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index 8f3982c03925..87a06fcca284 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -618,17 +618,19 @@ skl_plane_get_hw_state(struct intel_plane *plane,
>  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	enum intel_display_power_domain power_domain;
>  	enum plane_id plane_id = plane->id;
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
>  	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = I915_READ(PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE;
>  
>  	*pipe = plane->pipe;
>  
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -882,17 +884,19 @@ vlv_plane_get_hw_state(struct intel_plane *plane,
>  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	enum intel_display_power_domain power_domain;
>  	enum plane_id plane_id = plane->id;
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
>  	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = I915_READ(SPCNTR(plane->pipe, plane_id)) & SP_ENABLE;
>  
>  	*pipe = plane->pipe;
>  
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -1051,17 +1055,19 @@ ivb_plane_get_hw_state(struct intel_plane *plane,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	enum intel_display_power_domain power_domain;
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
>  	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	ret =  I915_READ(SPRCTL(plane->pipe)) & SPRITE_ENABLE;
>  
>  	*pipe = plane->pipe;
>  
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> @@ -1217,17 +1223,19 @@ g4x_plane_get_hw_state(struct intel_plane *plane,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
>  	enum intel_display_power_domain power_domain;
> +	intel_wakeref_t wakeref;
>  	bool ret;
>  
>  	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	ret = I915_READ(DVSCNTR(plane->pipe)) & DVS_ENABLE;
>  
>  	*pipe = plane->pipe;
>  
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_vdsc.c b/drivers/gpu/drm/i915/intel_vdsc.c
> index 48537827616f..23abf03736e7 100644
> --- a/drivers/gpu/drm/i915/intel_vdsc.c
> +++ b/drivers/gpu/drm/i915/intel_vdsc.c
> @@ -1082,6 +1082,6 @@ void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state)
>  	I915_WRITE(dss_ctl2_reg, dss_ctl2_val);
>  
>  	/* Disable Power wells for VDSC/joining */
> -	intel_display_power_put(dev_priv,
> -				intel_dsc_power_domain(old_crtc_state));
> +	intel_display_power_put_unchecked(dev_priv,
> +					  intel_dsc_power_domain(old_crtc_state));
>  }
> diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c
> index bb1287020f80..d116fead8514 100644
> --- a/drivers/gpu/drm/i915/vlv_dsi.c
> +++ b/drivers/gpu/drm/i915/vlv_dsi.c
> @@ -959,13 +959,15 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
> +	intel_wakeref_t wakeref;
>  	enum port port;
>  	bool active = false;
>  
>  	DRM_DEBUG_KMS("\n");
>  
> -	if (!intel_display_power_get_if_enabled(dev_priv,
> -						encoder->power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv,
> +						     encoder->power_domain);
> +	if (!wakeref)
>  		return false;
>  
>  	/*
> @@ -1021,7 +1023,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
>  	}
>  
>  out_put_power:
> -	intel_display_power_put(dev_priv, encoder->power_domain);
> +	intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
>  
>  	return active;
>  }
> @@ -1574,6 +1576,7 @@ vlv_dsi_get_hw_panel_orientation(struct intel_connector *connector)
>  	enum drm_panel_orientation orientation;
>  	struct intel_plane *plane;
>  	struct intel_crtc *crtc;
> +	intel_wakeref_t wakeref;
>  	enum pipe pipe;
>  	u32 val;
>  
> @@ -1584,7 +1587,8 @@ vlv_dsi_get_hw_panel_orientation(struct intel_connector *connector)
>  	plane = to_intel_plane(crtc->base.primary);
>  
>  	power_domain = POWER_DOMAIN_PIPE(pipe);
> -	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
> +	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +	if (!wakeref)
>  		return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
>  
>  	val = I915_READ(DSPCNTR(plane->i9xx_plane));
> @@ -1596,7 +1600,7 @@ vlv_dsi_get_hw_panel_orientation(struct intel_connector *connector)
>  	else
>  		orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
>  
> -	intel_display_power_put(dev_priv, power_domain);
> +	intel_display_power_put(dev_priv, power_domain, wakeref);
>  
>  	return orientation;
>  }
> -- 
> 2.20.1
Quoting Mika Kuoppala (2019-01-10 15:51:33)
> Chris Wilson <chris@chris-wilson.co.uk> writes:
> > @@ -680,6 +682,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
> >       wakeref = intel_runtime_pm_get(dev_priv);
> >  
> >       if (IS_CHERRYVIEW(dev_priv)) {
> > +             intel_wakeref_t pref;
> > +
> 
> In here you are introducing a new, descriptive, power reference for display.
> But then you drop it after using it twice. And can't seem to find
> reason for inconsistency.

pref, pref, pref...

> >               seq_printf(m, "Master Interrupt Control:\t%08x\n",
> >                          I915_READ(GEN8_MASTER_IRQ));
> >  
> > @@ -695,8 +699,9 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
> >                       enum intel_display_power_domain power_domain;
> >  
> >                       power_domain = POWER_DOMAIN_PIPE(pipe);
> > -                     if (!intel_display_power_get_if_enabled(dev_priv,
> > -                                                             power_domain)) {
> > +                     pref = intel_display_power_get_if_enabled(dev_priv,
> > +                                                               power_domain);
> > +                     if (!pref) {

ah, it would have been chosen to fit 80cols.

> >                               seq_printf(m, "Pipe %c power disabled\n",
> >                                          pipe_name(pipe));
> >                               continue;
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > index f0a405604b75..44c1b21febba 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -344,6 +344,7 @@ struct intel_csr {
> >       uint32_t mmiodata[8];
> >       uint32_t dc_state;
> >       uint32_t allowed_dc_mask;
> > +     intel_wakeref_t wakeref;
> >  };
> >  
> >  enum i915_cache_level {
> > @@ -1982,6 +1983,7 @@ struct drm_i915_private {
> >                * is a slight delay before we do so.
> >                */
> >               intel_wakeref_t awake;
> > +             intel_wakeref_t power;
> 
> This prolly explains the prefs above :)

Possibly.

> > -     intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_A_IO);
> > -
> > -     if (intel_dsi->dual_link)
> > -             intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_B_IO);
> > +     for_each_dsi_port(port, intel_dsi->ports) {
> > +             intel_wakeref_t wakeref;
> > +
> > +             wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
> > +             if (wakeref) {
> > +                     intel_display_power_put(dev_priv,
> > +                                             port == PORT_A ?
> > +                                             POWER_DOMAIN_PORT_DDI_A_IO :
> > +                                             POWER_DOMAIN_PORT_DDI_B_IO,
> > +                                             wakeref);
> > +             }
> > +     }
> 
> Ok, well. I have been trying to figure out what really is going on here.
> 
> First it seems that you fix a bug. We take refs for each dsi port but
> only release once special casing 'dual_link' without this patch.
> 
> Second, all the hw access is before getting the refs, looking
> suspicious.

There's always been two, just this moves into a for(;;). I don't think
it was buggy, but I do think the for(;;) has the advantage of being
clearer that it operates over all the ports and wakerefs.

> > @@ -15808,12 +15827,13 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
> >                            struct drm_modeset_acquire_ctx *ctx)
> >  {
> >       struct drm_i915_private *dev_priv = to_i915(dev);
> > -     struct intel_crtc *crtc;
> >       struct intel_crtc_state *crtc_state;
> >       struct intel_encoder *encoder;
> > +     struct intel_crtc *crtc;
> 
> Not that I mind but I don't understand the reasoning
> behind the change of order on this and on few other places in this
> patch.

Just quietly moving everyone over to a tidy set of variable definitions
(we are not meant to grow Christmas trees as part of the kernel coding
style).

> > -/**
> > - * intel_display_power_put - release a power domain reference
> > - * @dev_priv: i915 device instance
> > - * @domain: power domain to reference
> > - *
> > - * This function drops the power domain reference obtained by
> > - * intel_display_power_get() and might power down the corresponding hardware
> > - * block right away if this is the last reference.
> > - */
> > -void intel_display_power_put(struct drm_i915_private *dev_priv,
> > -                          enum intel_display_power_domain domain)
> > +static void __intel_display_power_put(struct drm_i915_private *dev_priv,
> > +                                   enum intel_display_power_domain domain)
> >  {
> >       struct i915_power_domains *power_domains;
> >       struct i915_power_well *power_well;
> > @@ -1947,10 +1944,34 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
> >               intel_power_well_put(dev_priv, power_well);
> >  
> >       mutex_unlock(&power_domains->lock);
> > +}
> >  
> > +/**
> > + * intel_display_power_put - release a power domain reference
> 
> +unchecked? or is this in wrong place.

unchecked doesn't exist, you just need a stronger pair of glasses.

So the only API documented interface is the full version that requires
you take ownership of your wakeref, we don't tempt you with the easy
version that is meant to only exist for transitioning
-Chris
Chris Wilson <chris@chris-wilson.co.uk> writes:

> Quoting Mika Kuoppala (2019-01-10 15:51:33)
>> Chris Wilson <chris@chris-wilson.co.uk> writes:
>> > @@ -680,6 +682,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
>> >       wakeref = intel_runtime_pm_get(dev_priv);
>> >  
>> >       if (IS_CHERRYVIEW(dev_priv)) {
>> > +             intel_wakeref_t pref;
>> > +
>> 
>> In here you are introducing a new, descriptive, power reference for display.
>> But then you drop it after using it twice. And can't seem to find
>> reason for inconsistency.
>
> pref, pref, pref...
>
>> >               seq_printf(m, "Master Interrupt Control:\t%08x\n",
>> >                          I915_READ(GEN8_MASTER_IRQ));
>> >  
>> > @@ -695,8 +699,9 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
>> >                       enum intel_display_power_domain power_domain;
>> >  
>> >                       power_domain = POWER_DOMAIN_PIPE(pipe);
>> > -                     if (!intel_display_power_get_if_enabled(dev_priv,
>> > -                                                             power_domain)) {
>> > +                     pref = intel_display_power_get_if_enabled(dev_priv,
>> > +                                                               power_domain);
>> > +                     if (!pref) {
>
> ah, it would have been chosen to fit 80cols.

You should have adopted it then fully! :)
>
>> >                               seq_printf(m, "Pipe %c power disabled\n",
>> >                                          pipe_name(pipe));
>> >                               continue;
>> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> > index f0a405604b75..44c1b21febba 100644
>> > --- a/drivers/gpu/drm/i915/i915_drv.h
>> > +++ b/drivers/gpu/drm/i915/i915_drv.h
>> > @@ -344,6 +344,7 @@ struct intel_csr {
>> >       uint32_t mmiodata[8];
>> >       uint32_t dc_state;
>> >       uint32_t allowed_dc_mask;
>> > +     intel_wakeref_t wakeref;
>> >  };
>> >  
>> >  enum i915_cache_level {
>> > @@ -1982,6 +1983,7 @@ struct drm_i915_private {
>> >                * is a slight delay before we do so.
>> >                */
>> >               intel_wakeref_t awake;
>> > +             intel_wakeref_t power;
>> 
>> This prolly explains the prefs above :)
>
> Possibly.
>
>> > -     intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_A_IO);
>> > -
>> > -     if (intel_dsi->dual_link)
>> > -             intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_B_IO);
>> > +     for_each_dsi_port(port, intel_dsi->ports) {
>> > +             intel_wakeref_t wakeref;
>> > +
>> > +             wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]);
>> > +             if (wakeref) {
>> > +                     intel_display_power_put(dev_priv,
>> > +                                             port == PORT_A ?
>> > +                                             POWER_DOMAIN_PORT_DDI_A_IO :
>> > +                                             POWER_DOMAIN_PORT_DDI_B_IO,
>> > +                                             wakeref);
>> > +             }
>> > +     }
>> 
>> Ok, well. I have been trying to figure out what really is going on here.
>> 
>> First it seems that you fix a bug. We take refs for each dsi port but
>> only release once special casing 'dual_link' without this patch.
>> 
>> Second, all the hw access is before getting the refs, looking
>> suspicious.
>
> There's always been two, just this moves into a for(;;). I don't think
> it was buggy, but I do think the for(;;) has the advantage of being
> clearer that it operates over all the ports and wakerefs.

Agreed that your patch makes it more clear.

I am still suspicious about the ordering, hopefully there is
upper lever pdomain to cover access. But that is not
problem for this patch.

Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>

>
>> > @@ -15808,12 +15827,13 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
>> >                            struct drm_modeset_acquire_ctx *ctx)
>> >  {
>> >       struct drm_i915_private *dev_priv = to_i915(dev);
>> > -     struct intel_crtc *crtc;
>> >       struct intel_crtc_state *crtc_state;
>> >       struct intel_encoder *encoder;
>> > +     struct intel_crtc *crtc;
>> 
>> Not that I mind but I don't understand the reasoning
>> behind the change of order on this and on few other places in this
>> patch.
>
> Just quietly moving everyone over to a tidy set of variable definitions
> (we are not meant to grow Christmas trees as part of the kernel coding
> style).
>
>> > -/**
>> > - * intel_display_power_put - release a power domain reference
>> > - * @dev_priv: i915 device instance
>> > - * @domain: power domain to reference
>> > - *
>> > - * This function drops the power domain reference obtained by
>> > - * intel_display_power_get() and might power down the corresponding hardware
>> > - * block right away if this is the last reference.
>> > - */
>> > -void intel_display_power_put(struct drm_i915_private *dev_priv,
>> > -                          enum intel_display_power_domain domain)
>> > +static void __intel_display_power_put(struct drm_i915_private *dev_priv,
>> > +                                   enum intel_display_power_domain domain)
>> >  {
>> >       struct i915_power_domains *power_domains;
>> >       struct i915_power_well *power_well;
>> > @@ -1947,10 +1944,34 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
>> >               intel_power_well_put(dev_priv, power_well);
>> >  
>> >       mutex_unlock(&power_domains->lock);
>> > +}
>> >  
>> > +/**
>> > + * intel_display_power_put - release a power domain reference
>> 
>> +unchecked? or is this in wrong place.
>
> unchecked doesn't exist, you just need a stronger pair of glasses.
>
> So the only API documented interface is the full version that requires
> you take ownership of your wakeref, we don't tempt you with the easy
> version that is meant to only exist for transitioning
> -Chris