aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEgbert Eich <eich@suse.de>2013-04-16 07:36:54 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-04-18 03:43:28 -0400
commitb543fb0464ddf30a5b554957fd212eb7a2acac65 (patch)
tree65d2faf5174a052f75d3fff6b5b9b2b216a9f954
parent08e1413d95b50b19259fe2e425885030f93c7b85 (diff)
drm/i915: Add HPD IRQ storm detection (v5)
Add a hotplug IRQ storm detection (triggered when a hotplug interrupt fires more than 5 times / sec). 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. v2: Fixed comment. v3: Reordered drm_i915_private: moved hpd state tracking to hotplug work stuff. v4: Followed by Jesse Barnes to use a time_..() macro. v5: Fixed coding style as suggested by Jani Nikula. Signed-off-by: Egbert Eich <eich@suse.de> Acked-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h9
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c69
2 files changed, 66 insertions, 12 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index b5a495a97ea7..7b613c2280f1 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -932,6 +932,15 @@ typedef struct drm_i915_private {
932 932
933 struct work_struct hotplug_work; 933 struct work_struct hotplug_work;
934 bool enable_hotplug_processing; 934 bool enable_hotplug_processing;
935 struct {
936 unsigned long hpd_last_jiffies;
937 int hpd_cnt;
938 enum {
939 HPD_ENABLED = 0,
940 HPD_DISABLED = 1,
941 HPD_MARK_DISABLED = 2
942 } hpd_mark;
943 } hpd_stats[HPD_NUM_PINS];
935 944
936 int num_pch_pll; 945 int num_pch_pll;
937 int num_plane; 946 int num_plane;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index e97bbb2abd59..5ac1291c5853 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -582,6 +582,40 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
582 queue_work(dev_priv->wq, &dev_priv->rps.work); 582 queue_work(dev_priv->wq, &dev_priv->rps.work);
583} 583}
584 584
585#define HPD_STORM_DETECT_PERIOD 1000
586#define HPD_STORM_THRESHOLD 5
587
588static inline void hotplug_irq_storm_detect(struct drm_device *dev,
589 u32 hotplug_trigger,
590 const u32 *hpd)
591{
592 drm_i915_private_t *dev_priv = dev->dev_private;
593 unsigned long irqflags;
594 int i;
595
596 spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
597
598 for (i = 1; i < HPD_NUM_PINS; i++) {
599 if (!(hpd[i] & hotplug_trigger) ||
600 dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED)
601 continue;
602
603 if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies,
604 dev_priv->hpd_stats[i].hpd_last_jiffies
605 + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) {
606 dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies;
607 dev_priv->hpd_stats[i].hpd_cnt = 0;
608 } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) {
609 dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
610 DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
611 } else {
612 dev_priv->hpd_stats[i].hpd_cnt++;
613 }
614 }
615
616 spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
617}
618
585static void gmbus_irq_handler(struct drm_device *dev) 619static void gmbus_irq_handler(struct drm_device *dev)
586{ 620{
587 struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; 621 struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -650,13 +684,15 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
650 /* Consume port. Then clear IIR or we'll miss events */ 684 /* Consume port. Then clear IIR or we'll miss events */
651 if (iir & I915_DISPLAY_PORT_INTERRUPT) { 685 if (iir & I915_DISPLAY_PORT_INTERRUPT) {
652 u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 686 u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
687 u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
653 688
654 DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", 689 DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
655 hotplug_status); 690 hotplug_status);
656 if (hotplug_status & HOTPLUG_INT_STATUS_I915) 691 if (hotplug_trigger) {
692 hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915);
657 queue_work(dev_priv->wq, 693 queue_work(dev_priv->wq,
658 &dev_priv->hotplug_work); 694 &dev_priv->hotplug_work);
659 695 }
660 I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 696 I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
661 I915_READ(PORT_HOTPLUG_STAT); 697 I915_READ(PORT_HOTPLUG_STAT);
662 } 698 }
@@ -680,10 +716,12 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
680{ 716{
681 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 717 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
682 int pipe; 718 int pipe;
719 u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
683 720
684 if (pch_iir & SDE_HOTPLUG_MASK) 721 if (hotplug_trigger) {
722 hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx);
685 queue_work(dev_priv->wq, &dev_priv->hotplug_work); 723 queue_work(dev_priv->wq, &dev_priv->hotplug_work);
686 724 }
687 if (pch_iir & SDE_AUDIO_POWER_MASK) 725 if (pch_iir & SDE_AUDIO_POWER_MASK)
688 DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", 726 DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
689 (pch_iir & SDE_AUDIO_POWER_MASK) >> 727 (pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -726,10 +764,12 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
726{ 764{
727 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 765 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
728 int pipe; 766 int pipe;
767 u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
729 768
730 if (pch_iir & SDE_HOTPLUG_MASK_CPT) 769 if (hotplug_trigger) {
770 hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt);
731 queue_work(dev_priv->wq, &dev_priv->hotplug_work); 771 queue_work(dev_priv->wq, &dev_priv->hotplug_work);
732 772 }
733 if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) 773 if (pch_iir & SDE_AUDIO_POWER_MASK_CPT)
734 DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", 774 DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
735 (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> 775 (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -2621,13 +2661,15 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
2621 if ((I915_HAS_HOTPLUG(dev)) && 2661 if ((I915_HAS_HOTPLUG(dev)) &&
2622 (iir & I915_DISPLAY_PORT_INTERRUPT)) { 2662 (iir & I915_DISPLAY_PORT_INTERRUPT)) {
2623 u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 2663 u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
2664 u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
2624 2665
2625 DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", 2666 DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
2626 hotplug_status); 2667 hotplug_status);
2627 if (hotplug_status & HOTPLUG_INT_STATUS_I915) 2668 if (hotplug_trigger) {
2669 hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915);
2628 queue_work(dev_priv->wq, 2670 queue_work(dev_priv->wq,
2629 &dev_priv->hotplug_work); 2671 &dev_priv->hotplug_work);
2630 2672 }
2631 I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 2673 I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
2632 POSTING_READ(PORT_HOTPLUG_STAT); 2674 POSTING_READ(PORT_HOTPLUG_STAT);
2633 } 2675 }
@@ -2854,15 +2896,18 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
2854 /* Consume port. Then clear IIR or we'll miss events */ 2896 /* Consume port. Then clear IIR or we'll miss events */
2855 if (iir & I915_DISPLAY_PORT_INTERRUPT) { 2897 if (iir & I915_DISPLAY_PORT_INTERRUPT) {
2856 u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 2898 u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
2899 u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ?
2900 HOTPLUG_INT_STATUS_G4X :
2901 HOTPLUG_INT_STATUS_I965);
2857 2902
2858 DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", 2903 DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
2859 hotplug_status); 2904 hotplug_status);
2860 if (hotplug_status & (IS_G4X(dev) ? 2905 if (hotplug_trigger) {
2861 HOTPLUG_INT_STATUS_G4X : 2906 hotplug_irq_storm_detect(dev, hotplug_trigger,
2862 HOTPLUG_INT_STATUS_I965)) 2907 IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965);
2863 queue_work(dev_priv->wq, 2908 queue_work(dev_priv->wq,
2864 &dev_priv->hotplug_work); 2909 &dev_priv->hotplug_work);
2865 2910 }
2866 I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 2911 I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
2867 I915_READ(PORT_HOTPLUG_STAT); 2912 I915_READ(PORT_HOTPLUG_STAT);
2868 } 2913 }