[PATCH 4/4] drm/i915: Avoid race of intel_crt_detect_hotplug() with HPD interrupt

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



A HPD interrupt may fire during intel_crt_detect_hotplug() - especially
when HPD interrupt storms occur.
Since the interrupt handler changes the enabled interrupt lines when it
detects a storm this races with intel_crt_detect_hotplug().
To avoid this, shiled the rmw cycles with IRQ save spinlocks.

Signed-off-by: Egbert Eich <eich@xxxxxxx>
---
 drivers/gpu/drm/i915/intel_crt.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index af5e43b..685f3de 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -376,9 +376,10 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 hotplug_en, orig, stat;
+	u32 hotplug_en, stat;
 	bool ret = false;
 	int i, tries = 0;
+	unsigned long irqflags;
 
 	if (HAS_PCH_SPLIT(dev))
 		return intel_ironlake_crt_detect_hotplug(connector);
@@ -395,12 +396,14 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
 		tries = 2;
 	else
 		tries = 1;
-	hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN);
-	hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
 
 	for (i = 0; i < tries ; i++) {
 		/* turn on the FORCE_DETECT */
-		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+		spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+		hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en |
+			   CRT_HOTPLUG_FORCE_DETECT);
+		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 		/* wait for FORCE_DETECT to go off */
 		if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
 			      CRT_HOTPLUG_FORCE_DETECT) == 0,
@@ -416,7 +419,11 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
 	I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
 
 	/* and put the bits back */
-	I915_WRITE(PORT_HOTPLUG_EN, orig);
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+	hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+	hotplug_en &= ~CRT_HOTPLUG_FORCE_DETECT;
+	I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
 	return ret;
 }
-- 
1.8.4.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux