@@ -9008,7 +9008,7 @@ void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915)
intel_dp_mst_suspend(i915);
/* MST is the last user of HPD work */
- intel_hpd_cancel_work(i915);
+ intel_hpd_suspend(i915);
/* poll work can call into fbdev, hence clean that up afterwards */
intel_fbdev_fini(i915);
@@ -303,6 +303,8 @@ static void i915_digport_work_func(struct work_struct *work)
u32 old_bits = 0;
spin_lock_irq(&dev_priv->irq_lock);
+ if (dev_priv->hotplug.suspended)
+ return spin_unlock_irq(&dev_priv->irq_lock);
long_port_mask = dev_priv->hotplug.long_port_mask;
dev_priv->hotplug.long_port_mask = 0;
short_port_mask = dev_priv->hotplug.short_port_mask;
@@ -353,6 +355,8 @@ void intel_hpd_trigger_irq(struct intel_digital_port *dig_port)
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
spin_lock_irq(&i915->irq_lock);
+ if (i915->hotplug.suspended)
+ return spin_unlock_irq(&i915->irq_lock);
i915->hotplug.short_port_mask |= BIT(dig_port->base.port);
spin_unlock_irq(&i915->irq_lock);
@@ -475,6 +479,9 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
spin_lock(&dev_priv->irq_lock);
+ if (dev_priv->hotplug.suspended)
+ return spin_unlock(&dev_priv->irq_lock);
+
/*
* Determine whether ->hpd_pulse() exists for each pin, and
* whether we have a short or a long pulse. This is needed
@@ -603,6 +610,7 @@ void intel_hpd_init(struct drm_i915_private *dev_priv)
* just to make the assert_spin_locked checks happy.
*/
spin_lock_irq(&dev_priv->irq_lock);
+ dev_priv->hotplug.suspended = false;
intel_hpd_irq_setup(dev_priv);
spin_unlock_irq(&dev_priv->irq_lock);
}
@@ -721,13 +729,14 @@ void intel_hpd_init_work(struct drm_i915_private *dev_priv)
intel_hpd_irq_storm_reenable_work);
}
-void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
+void intel_hpd_suspend(struct drm_i915_private *dev_priv)
{
if (!HAS_DISPLAY(dev_priv))
return;
spin_lock_irq(&dev_priv->irq_lock);
+ dev_priv->hotplug.suspended = true;
dev_priv->hotplug.long_port_mask = 0;
dev_priv->hotplug.short_port_mask = 0;
dev_priv->hotplug.event_bits = 0;
@@ -23,7 +23,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
void intel_hpd_trigger_irq(struct intel_digital_port *dig_port);
void intel_hpd_init(struct drm_i915_private *dev_priv);
void intel_hpd_init_work(struct drm_i915_private *dev_priv);
-void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
+void intel_hpd_suspend(struct drm_i915_private *dev_priv);
enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
enum port port);
bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
@@ -1079,7 +1079,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915)
intel_dp_mst_suspend(i915);
intel_runtime_pm_disable_interrupts(i915);
- intel_hpd_cancel_work(i915);
+ intel_hpd_suspend(i915);
intel_suspend_encoders(i915);
intel_shutdown_encoders(i915);
@@ -1148,7 +1148,7 @@ static int i915_drm_suspend(struct drm_device *dev)
intel_dp_mst_suspend(dev_priv);
intel_runtime_pm_disable_interrupts(dev_priv);
- intel_hpd_cancel_work(dev_priv);
+ intel_hpd_suspend(dev_priv);
intel_suspend_encoders(dev_priv);
@@ -106,6 +106,8 @@ struct vlv_s0ix_state;
#define HPD_STORM_DEFAULT_THRESHOLD 50
struct i915_hotplug {
+ bool suspended;
+
struct delayed_work hotplug_work;
const u32 *hpd, *pch_hpd;
HPD events during driver removal can be generated by hardware and software frameworks - drm_dp_mst, the former we can avoid by disabling interrupts, the latter can be triggered by any drm_dp_mst transaction, and this is too late. Introducing suspended flag allows to solve this chicken-egg problem. Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5950 Signed-off-by: Andrzej Hajda <andrzej.hajda@intel.com> --- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_hotplug.c | 11 ++++++++++- drivers/gpu/drm/i915/display/intel_hotplug.h | 2 +- drivers/gpu/drm/i915/i915_driver.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.h | 2 ++ 5 files changed, 16 insertions(+), 5 deletions(-)