[PATCH 10/29] drm/i915: Fix hotplug detection during suspend/unload

Imre Deak imre.deak at intel.com
Wed Dec 20 00:53:49 UTC 2023


Signed-off-by: Imre Deak <imre.deak at intel.com>
---
 .../gpu/drm/i915/display/intel_display_core.h |  6 +++
 drivers/gpu/drm/i915/display/intel_dp.c       |  2 +-
 drivers/gpu/drm/i915/display/intel_hotplug.c  | 43 +++++++++++++++----
 drivers/gpu/drm/i915/display/intel_hotplug.h  |  1 +
 4 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h
index 47297ed858223..91662456f82e4 100644
--- a/drivers/gpu/drm/i915/display/intel_display_core.h
+++ b/drivers/gpu/drm/i915/display/intel_display_core.h
@@ -172,6 +172,12 @@ struct intel_hotplug {
 	struct work_struct poll_init_work;
 	bool poll_enabled;
 
+	enum {
+		HOTPLUG_DETECTION_DISABLED,
+		HOTPLUG_DETECTION_HANDLER_ENABLED,
+		HOTPLUG_DETECTION_QUEUING_ENABLED,
+	} detection_state;
+
 	unsigned int hpd_storm_threshold;
 	/* Whether or not to count short HPD IRQs in HPD storms */
 	u8 hpd_short_storm_enabled;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index dc4844c533b61..92a1ca4aa5fb0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -6070,7 +6070,7 @@ static void intel_dp_oob_hotplug_event(struct drm_connector *connector,
 	spin_unlock_irq(&i915->irq_lock);
 
 	if (need_work)
-		queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0);
+		intel_hotplug_detection_queue_work(i915, 0);
 }
 
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c
index 673d8add084d1..4d8fa57a0ea75 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.c
@@ -302,6 +302,8 @@ intel_encoder_hotplug(struct intel_encoder *encoder,
 
 void intel_hotplug_detection_init(struct drm_i915_private *i915)
 {
+	i915->display.hotplug.detection_state = HOTPLUG_DETECTION_QUEUING_ENABLED;
+
 	intel_hpd_init(i915);
 	intel_hpd_poll_disable(i915);
 }
@@ -316,14 +318,39 @@ void intel_hotplug_detection_cleanup(struct drm_i915_private *i915)
 void intel_hotplug_detection_disable(struct drm_i915_private *i915)
 {
 	drm_kms_helper_poll_disable(&i915->drm);
+
+	drm_kms_helper_hotplug_event_disable(&i915->drm);
+
+	i915->display.hotplug.detection_state = HOTPLUG_DETECTION_HANDLER_ENABLED;
+	cancel_delayed_work_sync(&i915->display.hotplug.hotplug_work);
+
+	i915->display.hotplug.detection_state = HOTPLUG_DETECTION_DISABLED;
 }
 
 void intel_hotplug_detection_enable(struct drm_i915_private *i915)
 {
+	i915->display.hotplug.detection_state = HOTPLUG_DETECTION_QUEUING_ENABLED;
+
+	drm_kms_helper_hotplug_event_enable(&i915->drm);
+
 	intel_hpd_poll_disable(i915);
 	drm_kms_helper_poll_enable(&i915->drm);
 }
 
+void intel_hotplug_detection_queue_work(struct drm_i915_private *i915, int delay)
+{
+	if (i915->display.hotplug.detection_state >= HOTPLUG_DETECTION_QUEUING_ENABLED)
+		queue_delayed_work(i915->unordered_wq,
+				   &i915->display.hotplug.hotplug_work, delay);
+}
+
+static void intel_hotplug_detection_mod_work(struct drm_i915_private *i915, int delay)
+{
+	if (i915->display.hotplug.detection_state >= HOTPLUG_DETECTION_QUEUING_ENABLED)
+		mod_delayed_work(i915->unordered_wq,
+				 &i915->display.hotplug.hotplug_work, delay);
+}
+
 static bool intel_encoder_has_hpd_pulse(struct intel_encoder *encoder)
 {
 	return intel_encoder_is_dig_port(encoder) &&
@@ -373,8 +400,8 @@ static void i915_digport_work_func(struct work_struct *work)
 		spin_lock_irq(&dev_priv->irq_lock);
 		dev_priv->display.hotplug.event_bits |= old_bits;
 		spin_unlock_irq(&dev_priv->irq_lock);
-		queue_delayed_work(dev_priv->unordered_wq,
-				   &dev_priv->display.hotplug.hotplug_work, 0);
+
+		intel_hotplug_detection_queue_work(dev_priv, 0);
 	}
 }
 
@@ -493,9 +520,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
 		dev_priv->display.hotplug.retry_bits |= retry;
 		spin_unlock_irq(&dev_priv->irq_lock);
 
-		mod_delayed_work(dev_priv->unordered_wq,
-				 &dev_priv->display.hotplug.hotplug_work,
-				 msecs_to_jiffies(HPD_RETRY_DELAY));
+		intel_hotplug_detection_mod_work(dev_priv, msecs_to_jiffies(HPD_RETRY_DELAY));
 	}
 }
 
@@ -625,8 +650,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
 	if (queue_dig)
 		queue_work(dev_priv->display.hotplug.dp_wq, &dev_priv->display.hotplug.dig_port_work);
 	if (queue_hp)
-		queue_delayed_work(dev_priv->unordered_wq,
-				   &dev_priv->display.hotplug.hotplug_work, 0);
+		intel_hotplug_detection_queue_work(dev_priv, 0);
 }
 
 /**
@@ -883,7 +907,10 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
 	spin_unlock_irq(&dev_priv->irq_lock);
 
 	cancel_work_sync(&dev_priv->display.hotplug.dig_port_work);
-	cancel_delayed_work_sync(&dev_priv->display.hotplug.hotplug_work);
+
+	drm_WARN_ON(&dev_priv->drm,
+		    cancel_delayed_work_sync(&dev_priv->display.hotplug.hotplug_work));
+
 	cancel_work_sync(&dev_priv->display.hotplug.poll_init_work);
 	cancel_delayed_work_sync(&dev_priv->display.hotplug.reenable_work);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h b/drivers/gpu/drm/i915/display/intel_hotplug.h
index 5f5f1d72e8d72..ec55fa523de09 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.h
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.h
@@ -34,5 +34,6 @@ void intel_hotplug_detection_init(struct drm_i915_private *i915);
 void intel_hotplug_detection_cleanup(struct drm_i915_private *i915);
 void intel_hotplug_detection_disable(struct drm_i915_private *i915);
 void intel_hotplug_detection_enable(struct drm_i915_private *i915);
+void intel_hotplug_detection_queue_work(struct drm_i915_private *i915, int delay);
 
 #endif /* __INTEL_HOTPLUG_H__ */
-- 
2.39.2



More information about the Intel-gfx-trybot mailing list