This patch disables hotplug interrupts if an 'interrupt storm' has been detected. Noise on the interrupt line renders the hotplug interrupt useless: each hotplug event causes the devices to be rescanned which will will only increase the system load. Thus disable the hotplug interrupts and fall back to periodic device polling. Signed-off-by: Egbert Eich <eich at suse.de> --- drivers/gpu/drm/i915/i915_irq.c | 25 +++++++++++++++++++------ 1 files changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2da788f..aa4986d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -313,12 +313,13 @@ static void i915_hotplug_work_func(struct work_struct *work) drm_helper_hpd_irq_event(dev); } -static inline void hotplug_irq_storm_detect(struct drm_device *dev, u32 hotplug_trigger) +static inline int hotplug_irq_storm_detect(struct drm_device *dev, u32 hotplug_trigger) { struct drm_mode_config *mode_config = &dev->mode_config; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_connector *connector; unsigned long irqflags; + int ret = 0; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); @@ -335,12 +336,15 @@ static inline void hotplug_irq_storm_detect(struct drm_device *dev, u32 hotplug_ intel_connector->hpd_mark_disabled = 1; pr_warn("HPD interrupt storm on connector %s disabling\n", drm_get_connector_name(connector)); + ret = 1; } else intel_connector->hpd_cnt++; } } spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + return ret; } /* defined intel_pm.c */ @@ -652,7 +656,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger); + if (hotplug_irq_storm_detect(dev, hotplug_trigger)) + valleyview_enable_hotplug_irq(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } @@ -675,6 +680,8 @@ out: return ret; } +static void ibx_enable_hotplug_irq(struct drm_device *dev); + static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -682,7 +689,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) u32 hotplug_trigger = pch_iir & dev_priv->hotplug_supported_mask; if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger); + if (hotplug_irq_storm_detect(dev, hotplug_trigger)) + ibx_enable_hotplug_irq(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } if (pch_iir & SDE_AUDIO_POWER_MASK) @@ -720,6 +728,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); } +static void cpt_enable_hotplug_irq(struct drm_device *dev); + static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -727,7 +737,8 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) u32 hotplug_trigger = pch_iir & dev_priv->hotplug_supported_mask; if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger); + if (hotplug_irq_storm_detect(dev, hotplug_trigger)) + cpt_enable_hotplug_irq(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) @@ -2443,7 +2454,8 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger); + if (hotplug_irq_storm_detect(dev, hotplug_trigger)) + i915_enable_hotplug_irq(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } @@ -2694,7 +2706,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger); + if (hotplug_irq_storm_detect(dev, hotplug_trigger)) + i965_enable_hotplug_irq(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } -- 1.7.7