On Mon, Feb 25, 2013 at 12:06:53PM -0500, Egbert Eich wrote: > Add a hotplug IRQ storm detection (triggered when a hotplug interrupt > fires more than 5 times / sec). > Mask out this specific interrupt and revert to polling on the associated > output. Hmm, not convinced that just marking it as HPD_MARK_DISABLED does that. It certainly prevents the irq from sending the uevent, but we have not yet disabled the irq or enabled drm_kms_helper.poll for this connector. Though userspace polling is unaffected. > Rationale: > Despite of the many attempts to fix the problem with noisy hotplug > interrupt lines we are still seeing systems which have issues: > Once cause of noise seems to be bad routing of the hotplug line > on the board: cross talk from other signals seems to cause erronous > hotplug interrupts. This has been documented as an erratum for the > the i945GM chipset and thus hotplug support was disabled for this > chipset model but others seem to have this problem, too. > > We have seen this issue on a G35 motherboard for example: > Even different motherboards of the same model seem to behave > differently: while some only see only around 10-100 interrupts/s > others seem to see 5k or more. > We've also observed a dependency on the selected video mode. > > Also on certain laptops interrupt noise seems to occur duing > battery charging when the battery is at a certain charge levels. > > Thus we add a simple algorithm here that detects an 'interrupt storm' > condition. Looks sane. > > Signed-off-by: Egbert Eich <eich at suse.de> > --- > drivers/gpu/drm/i915/i915_drv.h | 9 +++++ > drivers/gpu/drm/i915/i915_irq.c | 63 +++++++++++++++++++++++++++++++------- > 2 files changed, 60 insertions(+), 12 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index d8604a6..6ca742d 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -1059,6 +1059,15 @@ typedef struct drm_i915_private { > /* Old dri1 support infrastructure, beware the dragons ya fools entering > * here! */ > struct i915_dri1_state dri1; > + struct { > + unsigned long hpd_last_jiffies; > + int hpd_cnt; > + enum { > + HPD_ENABLED = 0, > + HPD_DISABLED = 1, > + HPD_MARK_DISABLED = 2 > + } hpd_mark; > + } hpd_stats[HPD_NUM_PINS]; Please don't put it below dri1 -- as it may then be confused with our legacy burden. > } drm_i915_private_t; > > /* Iterate over initialised rings */ > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c > index c6ae7ae..08a0934 100644 > --- a/drivers/gpu/drm/i915/i915_irq.c > +++ b/drivers/gpu/drm/i915/i915_irq.c > @@ -587,6 +587,34 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, > queue_work(dev_priv->wq, &dev_priv->rps.work); > } > > +static inline void hotplug_irq_storm_detect(struct drm_device *dev, > + u32 hotplug_trigger, > + const u32 *hpd) > +{ > + drm_i915_private_t *dev_priv = dev->dev_private; > + unsigned long irqflags; > + int i; > + > + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); > + > + for (i = 1; i < HPD_NUM_PINS; i++) { > + if ((hpd[i] & hotplug_trigger) && > + dev_priv->hpd_stats[i].hpd_mark == HPD_ENABLED) { > + if (jiffies > (dev_priv->hpd_stats[i].hpd_last_jiffies + msecs_to_jiffies(1000)) || > + jiffies < dev_priv->hpd_stats[i].hpd_last_jiffies) { if (time_is_after(dev_priv->hpd_stats[i].hpd_last_jiffies + msecs_to_jiffies(1000))) Though it would be simpler if we just stored the adjusted hpd_last_jiffies. > + dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies; > + dev_priv->hpd_stats[i].hpd_cnt = 0; > + } else if (dev_priv->hpd_stats[i].hpd_cnt > 5) { > + dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; > + DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); > + } else > + dev_priv->hpd_stats[i].hpd_cnt++; > + } > + } > + > + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); > +} -- Chris Wilson, Intel Open Source Technology Centre