Message ID | 1361812019-20099-11-git-send-email-eich@suse.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Mon, Feb 25, 2013 at 12:06:57PM -0500, Egbert Eich wrote: > We disable hoptplug detection when we encounter a hotplug event > storm. Still hotplug detection is required on some outputs (like > Display Port). The interrupt storm may be only temporary (on certain > Dell Laptops for instance it happens at certain charging states of > the system). Thus we enable it after a certain grace period (2 minutes). > Should the interrupt storm persist it will be detected immediately > and it will be disabled again. > > Signed-off-by: Egbert Eich <eich@suse.de> Oops, just noticed that you have an ibx_hpd_irq_setup patch, too ;-) I think I'll go with since that one's just gotten a bit a beating in review from Ville. Hopfully that's not too ugly to rebase over ... -Daniel > --- > drivers/gpu/drm/i915/i915_drv.h | 2 + > drivers/gpu/drm/i915/i915_irq.c | 53 ++++++++++++++++++++++++++++++++++++++- > 2 files changed, 54 insertions(+), 1 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 6ca742d..58bee7a 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -1068,6 +1068,8 @@ typedef struct drm_i915_private { > HPD_MARK_DISABLED = 2 > } hpd_mark; > } hpd_stats[HPD_NUM_PINS]; > +#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) > + struct timer_list hotplug_reenable_timer; > } 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 8878fdd..ba598e3 100644 > --- a/drivers/gpu/drm/i915/i915_irq.c > +++ b/drivers/gpu/drm/i915/i915_irq.c > @@ -376,8 +376,11 @@ static void i915_hotplug_work_func(struct work_struct *work) > connector_disabled = true; > } > } > - if (connector_disabled) > + if (connector_disabled) { > drm_kms_helper_poll_enable(dev); /* if there were no outputs to poll, poll is disabled */ > + mod_timer(&dev_priv->hotplug_reenable_timer, > + jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); > + } > > spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); > > @@ -2253,6 +2256,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev) > if (!dev_priv) > return; > > + del_timer_sync(&dev_priv->hotplug_reenable_timer); > + > for_each_pipe(pipe) > I915_WRITE(PIPESTAT(pipe), 0xffff); > > @@ -2274,6 +2279,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev) > if (!dev_priv) > return; > > + del_timer_sync(&dev_priv->hotplug_reenable_timer); > + > I915_WRITE(HWSTAM, 0xffffffff); > > I915_WRITE(DEIMR, 0xffffffff); > @@ -2612,6 +2619,8 @@ static void i915_irq_uninstall(struct drm_device * dev) > drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; > int pipe; > > + del_timer_sync(&dev_priv->hotplug_reenable_timer); > + > if (I915_HAS_HOTPLUG(dev)) { > I915_WRITE(PORT_HOTPLUG_EN, 0); > I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); > @@ -2860,6 +2869,8 @@ static void i965_irq_uninstall(struct drm_device * dev) > if (!dev_priv) > return; > > + del_timer_sync(&dev_priv->hotplug_reenable_timer); > + > I915_WRITE(PORT_HOTPLUG_EN, 0); > I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); > > @@ -2875,6 +2886,44 @@ static void i965_irq_uninstall(struct drm_device * dev) > I915_WRITE(IIR, I915_READ(IIR)); > } > > +static void i915_reenable_hotplug_timer_func(unsigned long data) > +{ > + drm_i915_private_t *dev_priv = (drm_i915_private_t *)data; > + struct drm_device *dev = dev_priv->dev; > + struct drm_mode_config *mode_config = &dev->mode_config; > + unsigned long irqflags; > + int i; > + > + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); > + for (i = 1; i < HPD_NUM_PINS; i++) { > + if (dev_priv->hpd_stats[i].hpd_mark == HPD_MARK_DISABLED) { > + struct drm_connector *connector; > + > + dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; > + list_for_each_entry(connector, &mode_config->connector_list, head) { > + struct intel_connector *intel_connector = to_intel_connector(connector); > + > + if (intel_connector->encoder->hpd_pin == i) { > + if (connector->polled != intel_connector->polled) > + DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", > + drm_get_connector_name(connector)); > + connector->polled = intel_connector->polled; > + if (!connector->polled) > + connector->polled = DRM_CONNECTOR_POLL_HPD; > + } > + } > + > + if (IS_HASWELL(dev) || > + IS_IVYBRIDGE(dev) || > + (HAS_PCH_SPLIT(dev))) > + ibx_hpd_irq_setup(dev); > + else > + i915_hpd_irq_setup(dev); > + } > + } > + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); > +} > + > void intel_irq_init(struct drm_device *dev) > { > struct drm_i915_private *dev_priv = dev->dev_private; > @@ -2887,6 +2936,8 @@ void intel_irq_init(struct drm_device *dev) > setup_timer(&dev_priv->gpu_error.hangcheck_timer, > i915_hangcheck_elapsed, > (unsigned long) dev); > + setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func, > + (unsigned long) dev_priv); > > pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); > > -- > 1.7.7 >
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6ca742d..58bee7a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1068,6 +1068,8 @@ typedef struct drm_i915_private { HPD_MARK_DISABLED = 2 } hpd_mark; } hpd_stats[HPD_NUM_PINS]; +#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) + struct timer_list hotplug_reenable_timer; } 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 8878fdd..ba598e3 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -376,8 +376,11 @@ static void i915_hotplug_work_func(struct work_struct *work) connector_disabled = true; } } - if (connector_disabled) + if (connector_disabled) { drm_kms_helper_poll_enable(dev); /* if there were no outputs to poll, poll is disabled */ + mod_timer(&dev_priv->hotplug_reenable_timer, + jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); + } spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -2253,6 +2256,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + for_each_pipe(pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); @@ -2274,6 +2279,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + I915_WRITE(HWSTAM, 0xffffffff); I915_WRITE(DEIMR, 0xffffffff); @@ -2612,6 +2619,8 @@ static void i915_irq_uninstall(struct drm_device * dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -2860,6 +2869,8 @@ static void i965_irq_uninstall(struct drm_device * dev) if (!dev_priv) return; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -2875,6 +2886,44 @@ static void i965_irq_uninstall(struct drm_device * dev) I915_WRITE(IIR, I915_READ(IIR)); } +static void i915_reenable_hotplug_timer_func(unsigned long data) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *)data; + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + unsigned long irqflags; + int i; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + for (i = 1; i < HPD_NUM_PINS; i++) { + if (dev_priv->hpd_stats[i].hpd_mark == HPD_MARK_DISABLED) { + struct drm_connector *connector; + + dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_connector *intel_connector = to_intel_connector(connector); + + if (intel_connector->encoder->hpd_pin == i) { + if (connector->polled != intel_connector->polled) + DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", + drm_get_connector_name(connector)); + connector->polled = intel_connector->polled; + if (!connector->polled) + connector->polled = DRM_CONNECTOR_POLL_HPD; + } + } + + if (IS_HASWELL(dev) || + IS_IVYBRIDGE(dev) || + (HAS_PCH_SPLIT(dev))) + ibx_hpd_irq_setup(dev); + else + i915_hpd_irq_setup(dev); + } + } + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + void intel_irq_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2887,6 +2936,8 @@ void intel_irq_init(struct drm_device *dev) setup_timer(&dev_priv->gpu_error.hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); + setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func, + (unsigned long) dev_priv); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
We disable hoptplug detection when we encounter a hotplug event storm. Still hotplug detection is required on some outputs (like Display Port). The interrupt storm may be only temporary (on certain Dell Laptops for instance it happens at certain charging states of the system). Thus we enable it after a certain grace period (2 minutes). Should the interrupt storm persist it will be detected immediately and it will be disabled again. Signed-off-by: Egbert Eich <eich@suse.de> --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_irq.c | 53 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletions(-)