aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEgbert Eich <eich@suse.de>2013-04-16 07:36:58 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-04-18 03:43:30 -0400
commitac4c16c56cd41f320af064fc7bf28a1ec82c2278 (patch)
tree20c8e257be31b125785354f6e96985ec56fce0f9
parentcd569aed17b35b7be4567d0b277d23014ad34631 (diff)
drm/i915: Add Reenable Timer to turn Hotplug Detection back on (v4)
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. v2: Reordered drm_i915_private: moved hotplug_reenable_timer to hpd state tracker. v3: Clarified loop start value, Removed superfluous test for Ivybridge and Haswell, Restructured loop to avoid deep nesting (all suggested by Ville Syrjälä) v4: Fixed two bugs pointed out by Jani Nikula. Signed-off-by: Egbert Eich <eich@suse.de> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c52
2 files changed, 52 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7b613c2280f1..9b85fcdb3918 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -941,6 +941,7 @@ typedef struct drm_i915_private {
941 HPD_MARK_DISABLED = 2 941 HPD_MARK_DISABLED = 2
942 } hpd_mark; 942 } hpd_mark;
943 } hpd_stats[HPD_NUM_PINS]; 943 } hpd_stats[HPD_NUM_PINS];
944 struct timer_list hotplug_reenable_timer;
944 945
945 int num_pch_pll; 946 int num_pch_pll;
946 int num_plane; 947 int num_plane;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 565ea96f772f..0aa2ef0d2ae0 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -337,6 +337,8 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
337/* 337/*
338 * Handle hotplug events outside the interrupt handler proper. 338 * Handle hotplug events outside the interrupt handler proper.
339 */ 339 */
340#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000)
341
340static void i915_hotplug_work_func(struct work_struct *work) 342static void i915_hotplug_work_func(struct work_struct *work)
341{ 343{
342 drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 344 drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
@@ -375,8 +377,11 @@ static void i915_hotplug_work_func(struct work_struct *work)
375 /* if there were no outputs to poll, poll was disabled, 377 /* if there were no outputs to poll, poll was disabled,
376 * therefore make sure it's enabled when disabling HPD on 378 * therefore make sure it's enabled when disabling HPD on
377 * some connectors */ 379 * some connectors */
378 if (hpd_disabled) 380 if (hpd_disabled) {
379 drm_kms_helper_poll_enable(dev); 381 drm_kms_helper_poll_enable(dev);
382 mod_timer(&dev_priv->hotplug_reenable_timer,
383 jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY));
384 }
380 385
381 spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 386 spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
382 387
@@ -2367,6 +2372,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
2367 if (!dev_priv) 2372 if (!dev_priv)
2368 return; 2373 return;
2369 2374
2375 del_timer_sync(&dev_priv->hotplug_reenable_timer);
2376
2370 for_each_pipe(pipe) 2377 for_each_pipe(pipe)
2371 I915_WRITE(PIPESTAT(pipe), 0xffff); 2378 I915_WRITE(PIPESTAT(pipe), 0xffff);
2372 2379
@@ -2388,6 +2395,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
2388 if (!dev_priv) 2395 if (!dev_priv)
2389 return; 2396 return;
2390 2397
2398 del_timer_sync(&dev_priv->hotplug_reenable_timer);
2399
2391 I915_WRITE(HWSTAM, 0xffffffff); 2400 I915_WRITE(HWSTAM, 0xffffffff);
2392 2401
2393 I915_WRITE(DEIMR, 0xffffffff); 2402 I915_WRITE(DEIMR, 0xffffffff);
@@ -2767,6 +2776,8 @@ static void i915_irq_uninstall(struct drm_device * dev)
2767 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2776 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2768 int pipe; 2777 int pipe;
2769 2778
2779 del_timer_sync(&dev_priv->hotplug_reenable_timer);
2780
2770 if (I915_HAS_HOTPLUG(dev)) { 2781 if (I915_HAS_HOTPLUG(dev)) {
2771 I915_WRITE(PORT_HOTPLUG_EN, 0); 2782 I915_WRITE(PORT_HOTPLUG_EN, 0);
2772 I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 2783 I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -3011,6 +3022,8 @@ static void i965_irq_uninstall(struct drm_device * dev)
3011 if (!dev_priv) 3022 if (!dev_priv)
3012 return; 3023 return;
3013 3024
3025 del_timer_sync(&dev_priv->hotplug_reenable_timer);
3026
3014 I915_WRITE(PORT_HOTPLUG_EN, 0); 3027 I915_WRITE(PORT_HOTPLUG_EN, 0);
3015 I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 3028 I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
3016 3029
@@ -3026,6 +3039,41 @@ static void i965_irq_uninstall(struct drm_device * dev)
3026 I915_WRITE(IIR, I915_READ(IIR)); 3039 I915_WRITE(IIR, I915_READ(IIR));
3027} 3040}
3028 3041
3042static void i915_reenable_hotplug_timer_func(unsigned long data)
3043{
3044 drm_i915_private_t *dev_priv = (drm_i915_private_t *)data;
3045 struct drm_device *dev = dev_priv->dev;
3046 struct drm_mode_config *mode_config = &dev->mode_config;
3047 unsigned long irqflags;
3048 int i;
3049
3050 spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
3051 for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) {
3052 struct drm_connector *connector;
3053
3054 if (dev_priv->hpd_stats[i].hpd_mark != HPD_DISABLED)
3055 continue;
3056
3057 dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED;
3058
3059 list_for_each_entry(connector, &mode_config->connector_list, head) {
3060 struct intel_connector *intel_connector = to_intel_connector(connector);
3061
3062 if (intel_connector->encoder->hpd_pin == i) {
3063 if (connector->polled != intel_connector->polled)
3064 DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n",
3065 drm_get_connector_name(connector));
3066 connector->polled = intel_connector->polled;
3067 if (!connector->polled)
3068 connector->polled = DRM_CONNECTOR_POLL_HPD;
3069 }
3070 }
3071 }
3072 if (dev_priv->display.hpd_irq_setup)
3073 dev_priv->display.hpd_irq_setup(dev);
3074 spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
3075}
3076
3029void intel_irq_init(struct drm_device *dev) 3077void intel_irq_init(struct drm_device *dev)
3030{ 3078{
3031 struct drm_i915_private *dev_priv = dev->dev_private; 3079 struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3038,6 +3086,8 @@ void intel_irq_init(struct drm_device *dev)
3038 setup_timer(&dev_priv->gpu_error.hangcheck_timer, 3086 setup_timer(&dev_priv->gpu_error.hangcheck_timer,
3039 i915_hangcheck_elapsed, 3087 i915_hangcheck_elapsed,
3040 (unsigned long) dev); 3088 (unsigned long) dev);
3089 setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func,
3090 (unsigned long) dev_priv);
3041 3091
3042 pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); 3092 pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
3043 3093