aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorLyude <cpaul@redhat.com>2016-06-21 17:03:43 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2016-07-14 16:06:11 -0400
commitb236d7c8421969ac0693fc571e47ee5c2a62fb90 (patch)
treeff8053bce8d1162f03cae1603e0cd39a4991e877 /drivers/gpu/drm
parent9504a89247595b6c066c68aea0c34af1fc78d021 (diff)
drm/i915/vlv: Disable HPD in valleyview_crt_detect_hotplug()
One of the things preventing us from using polling is the fact that calling valleyview_crt_detect_hotplug() when there's a VGA cable connected results in sending another hotplug. With polling enabled when HPD is disabled, this results in a scenario like this: - We enable power wells and reset the ADPA - output_poll_exec does force probe on VGA, triggering a hpd - HPD handler waits for poll to unlock dev->mode_config.mutex - output_poll_exec shuts off the ADPA, unlocks dev->mode_config.mutex - HPD handler runs, resets ADPA and brings us back to the start This results in an endless irq storm getting sent from the ADPA whenever a VGA connector gets detected in the middle of polling. Somewhat based off of the "drm/i915: Disable CRT HPD around force trigger" patch Ville Syrjälä sent a while back Cc: stable@vger.kernel.org Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Lyude <cpaul@redhat.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c18
-rw-r--r--drivers/gpu/drm/i915/intel_hotplug.c27
3 files changed, 47 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a13b09890444..255293636e19 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2957,6 +2957,8 @@ void intel_hpd_init(struct drm_i915_private *dev_priv);
2957void intel_hpd_init_work(struct drm_i915_private *dev_priv); 2957void intel_hpd_init_work(struct drm_i915_private *dev_priv);
2958void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); 2958void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
2959bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port); 2959bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port);
2960bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
2961void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
2960 2962
2961/* i915_irq.c */ 2963/* i915_irq.c */
2962static inline void i915_queue_hangcheck(struct drm_i915_private *dev_priv) 2964static inline void i915_queue_hangcheck(struct drm_i915_private *dev_priv)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index d172930ac1e7..827b6ef4e9ae 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -329,10 +329,25 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
329 struct drm_device *dev = connector->dev; 329 struct drm_device *dev = connector->dev;
330 struct intel_crt *crt = intel_attached_crt(connector); 330 struct intel_crt *crt = intel_attached_crt(connector);
331 struct drm_i915_private *dev_priv = to_i915(dev); 331 struct drm_i915_private *dev_priv = to_i915(dev);
332 bool reenable_hpd;
332 u32 adpa; 333 u32 adpa;
333 bool ret; 334 bool ret;
334 u32 save_adpa; 335 u32 save_adpa;
335 336
337 /*
338 * Doing a force trigger causes a hpd interrupt to get sent, which can
339 * get us stuck in a loop if we're polling:
340 * - We enable power wells and reset the ADPA
341 * - output_poll_exec does force probe on VGA, triggering a hpd
342 * - HPD handler waits for poll to unlock dev->mode_config.mutex
343 * - output_poll_exec shuts off the ADPA, unlocks
344 * dev->mode_config.mutex
345 * - HPD handler runs, resets ADPA and brings us back to the start
346 *
347 * Just disable HPD interrupts here to prevent this
348 */
349 reenable_hpd = intel_hpd_disable(dev_priv, crt->base.hpd_pin);
350
336 save_adpa = adpa = I915_READ(crt->adpa_reg); 351 save_adpa = adpa = I915_READ(crt->adpa_reg);
337 DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); 352 DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
338 353
@@ -357,6 +372,9 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
357 372
358 DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret); 373 DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret);
359 374
375 if (reenable_hpd)
376 intel_hpd_enable(dev_priv, crt->base.hpd_pin);
377
360 return ret; 378 return ret;
361} 379}
362 380
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c
index 51434ec871f2..57f50a18fadd 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -510,3 +510,30 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
510 cancel_work_sync(&dev_priv->hotplug.hotplug_work); 510 cancel_work_sync(&dev_priv->hotplug.hotplug_work);
511 cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work); 511 cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work);
512} 512}
513
514bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin)
515{
516 bool ret = false;
517
518 if (pin == HPD_NONE)
519 return false;
520
521 spin_lock_irq(&dev_priv->irq_lock);
522 if (dev_priv->hotplug.stats[pin].state == HPD_ENABLED) {
523 dev_priv->hotplug.stats[pin].state = HPD_DISABLED;
524 ret = true;
525 }
526 spin_unlock_irq(&dev_priv->irq_lock);
527
528 return ret;
529}
530
531void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin)
532{
533 if (pin == HPD_NONE)
534 return;
535
536 spin_lock_irq(&dev_priv->irq_lock);
537 dev_priv->hotplug.stats[pin].state = HPD_ENABLED;
538 spin_unlock_irq(&dev_priv->irq_lock);
539}