diff options
author | Lyude <cpaul@redhat.com> | 2016-06-21 17:03:43 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-07-14 16:06:11 -0400 |
commit | b236d7c8421969ac0693fc571e47ee5c2a62fb90 (patch) | |
tree | ff8053bce8d1162f03cae1603e0cd39a4991e877 /drivers/gpu/drm | |
parent | 9504a89247595b6c066c68aea0c34af1fc78d021 (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.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_crt.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_hotplug.c | 27 |
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); | |||
2957 | void intel_hpd_init_work(struct drm_i915_private *dev_priv); | 2957 | void intel_hpd_init_work(struct drm_i915_private *dev_priv); |
2958 | void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); | 2958 | void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); |
2959 | bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port); | 2959 | bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port); |
2960 | bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin); | ||
2961 | void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin); | ||
2960 | 2962 | ||
2961 | /* i915_irq.c */ | 2963 | /* i915_irq.c */ |
2962 | static inline void i915_queue_hangcheck(struct drm_i915_private *dev_priv) | 2964 | static 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 | |||
514 | bool 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 | |||
531 | void 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 | } | ||