From af4a8e22a4aac7ec370afce670ec1b91a823a14d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 May 2014 10:37:01 +0100 Subject: [PATCH] drm/i915: Add a window for no hpd events after a modeset Some monitors seem to trigger a hpd soon after a modeset, yet remain inaccessible. This leads us to decide that the monitor is no longer connected, causing us to disconnect it via another modeset. This leads to another hpd interrupt where it is visible and another connect, and the cycle repeats. Try to masking this by giving the time for the monitor to settle before processing more hpd events after a modeset. Signed-off-by: Chris Wilson References: https://bugs.freedesktop.org/show_bug.cgi?id=73855 --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_irq.c | 14 +++++++++++++- drivers/gpu/drm/i915/intel_display.c | 3 ++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8b897195610c..486fcda9b786 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1333,6 +1333,8 @@ struct drm_i915_private { } hpd_stats[HPD_NUM_PINS]; u32 hpd_event_bits; struct timer_list hotplug_reenable_timer; + unsigned long last_modeset; + struct delayed_work hotplug_uevent_work; struct i915_fbc fbc; struct i915_drrs drrs; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9db087f8c668..5943bab57eb0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -970,6 +970,17 @@ static bool intel_hpd_irq_event(struct drm_device *dev, return true; } +static void i915_hotplug_uevent_work_func(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, struct drm_i915_private, hotplug_uevent_work.work); + long delay = dev_priv->last_modeset + 5*HZ - jiffies; + if (delay <= 0) + drm_kms_helper_hotplug_event(dev_priv->dev); + else + schedule_delayed_work(&dev_priv->hotplug_uevent_work, delay); +} + /* * Handle hotplug events outside the interrupt handler proper. */ @@ -1043,7 +1054,7 @@ static void i915_hotplug_work_func(struct work_struct *work) mutex_unlock(&mode_config->mutex); if (changed) - drm_kms_helper_hotplug_event(dev); + i915_hotplug_uevent_work_func(&dev_priv->hotplug_uevent_work.work); } static void intel_hpd_irq_uninstall(struct drm_i915_private *dev_priv) @@ -3974,6 +3985,7 @@ void intel_irq_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); + INIT_DELAYED_WORK(&dev_priv->hotplug_uevent_work, i915_hotplug_uevent_work_func); INIT_WORK(&dev_priv->gpu_error.work, i915_error_work_func); INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index af67c5cba25b..08f5b6369cf6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10074,6 +10074,8 @@ done: out: kfree(pipe_config); kfree(saved_mode); + + dev_priv->last_modeset = jiffies; return ret; } @@ -10084,7 +10086,6 @@ static int intel_set_mode(struct drm_crtc *crtc, int ret; ret = __intel_set_mode(crtc, mode, x, y, fb); - if (ret == 0) intel_modeset_check_state(crtc->dev); -- 2.0.0.rc0