Skip to content

Commit b236d7c

Browse files
Lyudedanvet
authored andcommitted
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: [email protected] Cc: Ville Syrjälä <[email protected]> Signed-off-by: Lyude <[email protected]> Signed-off-by: Daniel Vetter <[email protected]>
1 parent 9504a89 commit b236d7c

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2957,6 +2957,8 @@ void intel_hpd_init(struct drm_i915_private *dev_priv);
29572957
void intel_hpd_init_work(struct drm_i915_private *dev_priv);
29582958
void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
29592959
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);
29602962

29612963
/* i915_irq.c */
29622964
static inline void i915_queue_hangcheck(struct drm_i915_private *dev_priv)

drivers/gpu/drm/i915/intel_crt.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,25 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
329329
struct drm_device *dev = connector->dev;
330330
struct intel_crt *crt = intel_attached_crt(connector);
331331
struct drm_i915_private *dev_priv = to_i915(dev);
332+
bool reenable_hpd;
332333
u32 adpa;
333334
bool ret;
334335
u32 save_adpa;
335336

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+
336351
save_adpa = adpa = I915_READ(crt->adpa_reg);
337352
DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
338353

@@ -357,6 +372,9 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
357372

358373
DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret);
359374

375+
if (reenable_hpd)
376+
intel_hpd_enable(dev_priv, crt->base.hpd_pin);
377+
360378
return ret;
361379
}
362380

drivers/gpu/drm/i915/intel_hotplug.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,3 +510,30 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
510510
cancel_work_sync(&dev_priv->hotplug.hotplug_work);
511511
cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work);
512512
}
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+
}

0 commit comments

Comments
 (0)