All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/24] irq locking review
@ 2013-06-12 11:37 Daniel Vetter
  2013-06-12 11:37 ` [PATCH 01/24] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
                   ` (23 more replies)
  0 siblings, 24 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Hi all,

So here's my irq locking review, inspired by the VECS patches. The first part
(up to patch 14) deals mostly with display interrupts and especially
interactions between the hpd storm detection and the fifu underrun reporting.

Most of it is just unification, but there's two cases where locking wasn't
sufficient. Besides the cleanup it also reworks the fifo underrun reporting a
bit so that we also report underruns even when we can't enable the interrupt
(just in a delayed fashion). This is useful prep work for enabling fifo underrun
reporting on i9xx/vlv, since ther we don't ever have an interrupt. So only
delayed reporting is possible.

The second part streamlines the VECS-related interrupt handling. Contrary to my
claims I haven't found a real bug in there. But I still rest on my assertion
that the current code was too fragile, and the various shady comments did not
help in creating confidence, either. I've taken the oppportunity here though to
unify the interrupt enable sequence a bit, which should greatly help us in
keeping our sanity with the pc8+ patches.

I've tried to remove unecessary locking as much as possible (e.g. dropped irq
disabling wherever possible) so that the real required locking and ordering
sticks out more. One change I've considered but haven't (yet) done is to drop
the irq save/restore dance everywhere we know that spinlock nesting can't occur
(and is unlikely to ever get added). Again that would just better document that
no nasty spinlock nesting can happen (since lockdep viciously checks those
things). I'll probably do that in a follow-up series.

Comments, flames and review highly welcome.

Cheers, Daniel

Daniel Vetter (24):
  drm/i915: fix locking around ironlake_enable|disable_display_irq
  drm/i915: close tiny race in the ilk pcu even interrupt setup
  drm/i915: assert_spin_locked for pipestat interrupt enable/disable
  drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/
  drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler
  drm/i915: fold the queue_work into intel_hpd_irq_handler
  drm/i915: fold the no-irq check into intel_hpd_irq_handler
  drm/i915: fix hpd interrupt register locking
  drm/i915: extract ibx_display_interrupt_update
  drm/i915: remove SERR_INT clearing in the postinstall hook
  drm/i915: improve SERR_INT clearing for fifo underrun reporting
  drm/i915: improve GEN7_ERR_INT clearing for fifo underrun reporting
  drm/i915: kill lpt pch transcoder->crtc mapping code for fifo
    underruns
  drm/i915: irq handlers don't need interrupt-safe spinlocks
  drm/i915: streamline hsw_pm_irq_handler
  drm/i915: queue work outside spinlock in hsw_pm_irq_handler
  drm/i915: kill dev_priv->rps.lock
  drm/i915: unify ring irq refcounts (again)
  drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT
  drm/i915: kill bogus GTIIR clearing in vlv_preinstall hook
  drm/i915: unify PM interrupt preinstall sequence
  drm/i915: unify GT/PM irq postinstall code
  drm/i915: extract rps interrupt enable/disable helpers
  drm/i915: simplify rps interrupt enabling/disabling sequence

 drivers/gpu/drm/i915/i915_dma.c         |   1 -
 drivers/gpu/drm/i915/i915_drv.h         |   8 +-
 drivers/gpu/drm/i915/i915_irq.c         | 422 ++++++++++++++++----------------
 drivers/gpu/drm/i915/i915_reg.h         |   2 +
 drivers/gpu/drm/i915/intel_pm.c         |  65 +++--
 drivers/gpu/drm/i915/intel_ringbuffer.c |  31 ++-
 drivers/gpu/drm/i915/intel_ringbuffer.h |   5 +-
 7 files changed, 259 insertions(+), 275 deletions(-)

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 86+ messages in thread

* [PATCH 01/24] drm/i915: fix locking around ironlake_enable|disable_display_irq
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-25 12:26   ` [PATCH] " Daniel Vetter
  2013-06-12 11:37 ` [PATCH 02/24] drm/i915: close tiny race in the ilk pcu even interrupt setup Daniel Vetter
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

The haswell unclaimed register handling code forgot to take the
spinlock. Since this is in the context of the non-rentrant interupt
handler and we only have one interrupt handler it is sufficient to
just grab the spinlock - we do not need to exclude any other
interrupts from running on the same cpu.

To prevent such gaffles in the future sprinkle assert_spin_locked over
these functions. Unfornately this requires us to hold the spinlock in
the ironlake postinstall hook where it is not strictly required:
Currently that is run in single-threaded context and with userspace
exlcuded from running concurrent ioctls. Add a comment explaining
this.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index c482e8a..567945f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -95,6 +95,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev);
 static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((dev_priv->irq_mask & mask) != 0) {
 		dev_priv->irq_mask &= ~mask;
 		I915_WRITE(DEIMR, dev_priv->irq_mask);
@@ -105,6 +107,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 static void
 ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((dev_priv->irq_mask & mask) != mask) {
 		dev_priv->irq_mask |= mask;
 		I915_WRITE(DEIMR, dev_priv->irq_mask);
@@ -1218,8 +1222,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 	/* On Haswell, also mask ERR_INT because we don't want to risk
 	 * generating "unclaimed register" interrupts from inside the interrupt
 	 * handler. */
-	if (IS_HASWELL(dev))
+	if (IS_HASWELL(dev)) {
+		spin_lock(&dev_priv->irq_lock);
 		ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+		spin_unlock(&dev_priv->irq_lock);
+	}
 
 	gt_iir = I915_READ(GTIIR);
 	if (gt_iir) {
@@ -1272,8 +1279,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 		ret = IRQ_HANDLED;
 	}
 
-	if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev))
+	if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev)) {
+		spin_lock(&dev_priv->irq_lock);
 		ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+		spin_unlock(&dev_priv->irq_lock);
+	}
 
 	I915_WRITE(DEIER, de_ier);
 	POSTING_READ(DEIER);
@@ -2633,6 +2643,8 @@ static void ibx_irq_postinstall(struct drm_device *dev)
 
 static int ironlake_irq_postinstall(struct drm_device *dev)
 {
+	unsigned long irqflags;
+
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	/* enable kind of interrupts always enabled */
 	u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
@@ -2671,7 +2683,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 		/* Clear & enable PCU event interrupts */
 		I915_WRITE(DEIIR, DE_PCU_EVENT);
 		I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
+
+		/* spinlocking not required here for correctness since interrupt
+		 * setup is guaranteed to run in single-threaded context. But we
+		 * need it to make the assert_spin_locked happy. */
+		spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 		ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
+		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 	}
 
 	return 0;
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 02/24] drm/i915: close tiny race in the ilk pcu even interrupt setup
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
  2013-06-12 11:37 ` [PATCH 01/24] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-26 21:20   ` Paulo Zanoni
  2013-06-12 11:37 ` [PATCH 03/24] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
                   ` (21 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

By the time we write DEIER in the postinstall hook the interrupt
handler could run any time. And it does modify DEIER to handle
interrupts.

Hence the DEIER read-modify-write cycle for enabling the PCU event
source is racy. Close this races the same way we handle vblank
interrupts: Unconditionally enable the interrupt in the IER register,
but conditionally mask it in IMR. The later poses no such race since
the interrupt handler does not touch DEIMR.

Also update the comment, the clearing has already happened
unconditionally above.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 567945f..969da20 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2658,7 +2658,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 	/* should always can generate irq */
 	I915_WRITE(DEIIR, I915_READ(DEIIR));
 	I915_WRITE(DEIMR, dev_priv->irq_mask);
-	I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK);
+	I915_WRITE(DEIER, display_mask |
+			  DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT);
 	POSTING_READ(DEIER);
 
 	dev_priv->gt_irq_mask = ~0;
@@ -2680,11 +2681,9 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 	ibx_irq_postinstall(dev);
 
 	if (IS_IRONLAKE_M(dev)) {
-		/* Clear & enable PCU event interrupts */
-		I915_WRITE(DEIIR, DE_PCU_EVENT);
-		I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
-
-		/* spinlocking not required here for correctness since interrupt
+		/* Clear & enable PCU event interrupts
+		 *
+		 * spinlocking not required here for correctness since interrupt
 		 * setup is guaranteed to run in single-threaded context. But we
 		 * need it to make the assert_spin_locked happy. */
 		spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 03/24] drm/i915: assert_spin_locked for pipestat interrupt enable/disable
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
  2013-06-12 11:37 ` [PATCH 01/24] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
  2013-06-12 11:37 ` [PATCH 02/24] drm/i915: close tiny race in the ilk pcu even interrupt setup Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-26 21:44   ` Paulo Zanoni
  2013-06-12 11:37 ` [PATCH 04/24] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Just to keep the paranoia equal also sprinkle locking asserts over the
pipestat interrupt enable/disable functions.

Again this results in false positives in the interrupt setup. Add
bogo-locking for these and a big comment explaining why it's there and
that it's indeed unnecessary.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 969da20..c0b6c85 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -329,6 +329,8 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 	u32 reg = PIPESTAT(pipe);
 	u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((pipestat & mask) == mask)
 		return;
 
@@ -344,6 +346,8 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 	u32 reg = PIPESTAT(pipe);
 	u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((pipestat & mask) == 0)
 		return;
 
@@ -2681,7 +2685,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 	ibx_irq_postinstall(dev);
 
 	if (IS_IRONLAKE_M(dev)) {
-		/* Clear & enable PCU event interrupts
+		/* Enable PCU event interrupts
 		 *
 		 * spinlocking not required here for correctness since interrupt
 		 * setup is guaranteed to run in single-threaded context. But we
@@ -2758,6 +2762,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 	u32 gt_irqs;
 	u32 enable_mask;
 	u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
+	unsigned long irqflags;
 
 	enable_mask = I915_DISPLAY_PORT_INTERRUPT;
 	enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
@@ -2783,9 +2788,13 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 	I915_WRITE(PIPESTAT(1), 0xffff);
 	POSTING_READ(VLV_IER);
 
+	/* Interrup setup is already guaranteed to be single-threaded, this is
+	 * just to make the assert_spin_locked check happy. */
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, 0, pipestat_enable);
 	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
 	i915_enable_pipestat(dev_priv, 1, pipestat_enable);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
 	I915_WRITE(VLV_IIR, 0xffffffff);
 	I915_WRITE(VLV_IIR, 0xffffffff);
@@ -3267,6 +3276,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	u32 enable_mask;
 	u32 error_mask;
+	unsigned long irqflags;
 
 	/* Unmask the interrupts that we always want on. */
 	dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
@@ -3285,7 +3295,11 @@ static int i965_irq_postinstall(struct drm_device *dev)
 	if (IS_G4X(dev))
 		enable_mask |= I915_BSD_USER_INTERRUPT;
 
+	/* Interrup setup is already guaranteed to be single-threaded, this is
+	 * just to make the assert_spin_locked check happy. */
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
 	/*
 	 * Enable some error detection, note the instruction error mask
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 04/24] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (2 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 03/24] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 14:22   ` Egbert Eich
  2013-06-12 11:37 ` [PATCH 05/24] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler Daniel Vetter
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

The combination of Paulo's fifo underrun detection code and Egbert's
hpd storm handling code unfortunately made the hpd storm handling code
racy.

To avoid duplicating tricky interrupt locking code over all platforms
start with a bit of refactoring. This patch is the very first step
since in the end the irq storm handling code will handle all hotplug
logic (and so also encapsulate the locking nicely).

Cc: Egbert Eich <eich@suse.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index c0b6c85..ab3368e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -878,9 +878,9 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
 #define HPD_STORM_DETECT_PERIOD 1000
 #define HPD_STORM_THRESHOLD 5
 
-static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
-					    u32 hotplug_trigger,
-					    const u32 *hpd)
+static inline bool intel_hpd_irq_handler(struct drm_device *dev,
+					 u32 hotplug_trigger,
+					 const u32 *hpd)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned long irqflags;
@@ -1021,7 +1021,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 					 hotplug_status);
 			if (hotplug_trigger) {
-				if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
 					i915_hpd_irq_setup(dev);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
@@ -1052,7 +1052,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
 	if (hotplug_trigger) {
-		if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx))
+		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx))
 			ibx_hpd_irq_setup(dev);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
@@ -1157,7 +1157,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
 	if (hotplug_trigger) {
-		if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt))
+		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt))
 			ibx_hpd_irq_setup(dev);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
@@ -3174,7 +3174,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
 					i915_hpd_irq_setup(dev);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
@@ -3420,7 +3420,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (hotplug_irq_storm_detect(dev, hotplug_trigger,
+				if (intel_hpd_irq_handler(dev, hotplug_trigger,
 							    IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965))
 					i915_hpd_irq_setup(dev);
 				queue_work(dev_priv->wq,
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 05/24] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (3 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 04/24] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
       [not found]   ` <20920.34096.704203.67316@linux-qknr.site>
  2013-06-12 11:37 ` [PATCH 06/24] drm/i915: fold the queue_work " Daniel Vetter
                   ` (18 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

We already have a vfunc for this (and other parts of the hpd storm
handling code already use it).

Cc: Egbert Eich <eich@suse.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index ab3368e..1f8d914 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -88,9 +88,6 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
 };
 
-static void ibx_hpd_irq_setup(struct drm_device *dev);
-static void i915_hpd_irq_setup(struct drm_device *dev);
-
 /* For display hotplug interrupt */
 static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
@@ -878,14 +875,14 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
 #define HPD_STORM_DETECT_PERIOD 1000
 #define HPD_STORM_THRESHOLD 5
 
-static inline bool intel_hpd_irq_handler(struct drm_device *dev,
+static inline void intel_hpd_irq_handler(struct drm_device *dev,
 					 u32 hotplug_trigger,
 					 const u32 *hpd)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned long irqflags;
 	int i;
-	bool ret = false;
+	bool storm_detected = false;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
@@ -905,7 +902,7 @@ static inline bool intel_hpd_irq_handler(struct drm_device *dev,
 			dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
 			dev_priv->hpd_event_bits &= ~(1 << i);
 			DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
-			ret = true;
+			storm_detected = true;
 		} else {
 			dev_priv->hpd_stats[i].hpd_cnt++;
 		}
@@ -913,7 +910,8 @@ static inline bool intel_hpd_irq_handler(struct drm_device *dev,
 
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
-	return ret;
+	if (storm_detected)
+		dev_priv->display.hpd_irq_setup(dev);
 }
 
 static void gmbus_irq_handler(struct drm_device *dev)
@@ -1021,8 +1019,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 					 hotplug_status);
 			if (hotplug_trigger) {
-				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
-					i915_hpd_irq_setup(dev);
+				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 			}
@@ -1052,8 +1049,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
 	if (hotplug_trigger) {
-		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx))
-			ibx_hpd_irq_setup(dev);
+		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
@@ -1157,8 +1153,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
 	if (hotplug_trigger) {
-		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt))
-			ibx_hpd_irq_setup(dev);
+		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
@@ -3174,8 +3169,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
-					i915_hpd_irq_setup(dev);
+				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 			}
@@ -3420,9 +3414,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (intel_hpd_irq_handler(dev, hotplug_trigger,
-							    IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965))
-					i915_hpd_irq_setup(dev);
+				intel_hpd_irq_handler(dev, hotplug_trigger,
+						      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 			}
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 06/24] drm/i915: fold the queue_work into intel_hpd_irq_handler
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (4 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 05/24] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 14:29   ` Egbert Eich
  2013-06-12 11:37 ` [PATCH 07/24] drm/i915: fold the no-irq check " Daniel Vetter
                   ` (17 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

Everywhere the same.

Cc: Egbert Eich <eich@suse.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 1f8d914..38bb26f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -912,6 +912,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 
 	if (storm_detected)
 		dev_priv->display.hpd_irq_setup(dev);
+
+	queue_work(dev_priv->wq,
+		   &dev_priv->hotplug_work);
 }
 
 static void gmbus_irq_handler(struct drm_device *dev)
@@ -1020,8 +1023,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 					 hotplug_status);
 			if (hotplug_trigger) {
 				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-				queue_work(dev_priv->wq,
-					   &dev_priv->hotplug_work);
 			}
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
@@ -1050,7 +1051,6 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 
 	if (hotplug_trigger) {
 		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
-		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -1154,7 +1154,6 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 
 	if (hotplug_trigger) {
 		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
-		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -3170,8 +3169,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 				  hotplug_status);
 			if (hotplug_trigger) {
 				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-				queue_work(dev_priv->wq,
-					   &dev_priv->hotplug_work);
 			}
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			POSTING_READ(PORT_HOTPLUG_STAT);
@@ -3416,8 +3413,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			if (hotplug_trigger) {
 				intel_hpd_irq_handler(dev, hotplug_trigger,
 						      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965);
-				queue_work(dev_priv->wq,
-					   &dev_priv->hotplug_work);
 			}
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 07/24] drm/i915: fold the no-irq check into intel_hpd_irq_handler
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (5 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 06/24] drm/i915: fold the queue_work " Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 14:33   ` Egbert Eich
  2013-06-12 11:37 ` [PATCH 08/24] " Daniel Vetter
                   ` (16 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

The usual pattern for our sub-function irq_handlers is that they check
for the no-irq case themselves. This results in more streamlined code
in the upper irq handlers.

Cc: Egbert Eich <eich@suse.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 38bb26f..1815891 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -884,6 +884,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 	int i;
 	bool storm_detected = false;
 
+	if (!hotplug_trigger)
+		return;
+
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
 	for (i = 1; i < HPD_NUM_PINS; i++) {
@@ -1021,9 +1024,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 					 hotplug_status);
-			if (hotplug_trigger) {
-				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-			}
+
+			intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
 		}
@@ -1049,9 +1052,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 	int pipe;
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
-	if (hotplug_trigger) {
-		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
-	}
+	intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
+
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
 			       SDE_AUDIO_POWER_SHIFT);
@@ -1152,9 +1154,8 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 	int pipe;
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
-	if (hotplug_trigger) {
-		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
-	}
+	intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
+
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
 			       SDE_AUDIO_POWER_SHIFT_CPT);
@@ -3167,9 +3168,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
-			if (hotplug_trigger) {
-				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-			}
+
+			intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			POSTING_READ(PORT_HOTPLUG_STAT);
 		}
@@ -3410,10 +3411,10 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
-			if (hotplug_trigger) {
-				intel_hpd_irq_handler(dev, hotplug_trigger,
-						      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965);
-			}
+
+			intel_hpd_irq_handler(dev, hotplug_trigger,
+					      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965);
+
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
 		}
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 08/24] drm/i915: fix hpd interrupt register locking
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (6 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 07/24] drm/i915: fold the no-irq check " Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 14:59   ` Egbert Eich
  2013-06-12 11:37 ` [PATCH 09/24] drm/i915: extract ibx_display_interrupt_update Daniel Vetter
                   ` (15 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

Our interrupt handler (in hardird context) could race with the timer
(in softirq context), hence we need to hold the spinlock around the
call to ->hdp_irq_setup in intel_hpd_irq_handler, too.

But as an optimization (and more so to clarify things) we don't need
to do the irqsave/restore dance in the hardirq context.

Note also that on ilk+ the race isn't just against the hotplug
reenable timer, but also against the fifo underrun reporting. That one
also modifies the SDEIMR register (again protected by the same
dev_priv->irq_lock).

To lock things down again sprinkle a assert_spin_locked. But exclude
the functions touching SDEIMR for now, I want to extract them all into
a new helper function (like we do already for pipestate, display
interrupts and all the various gt interrupts).

Cc: Egbert Eich <eich@suse.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 1815891..95e15cd 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -880,15 +880,13 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 					 const u32 *hpd)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	unsigned long irqflags;
 	int i;
 	bool storm_detected = false;
 
 	if (!hotplug_trigger)
 		return;
 
-	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-
+	spin_lock(&dev_priv->irq_lock);
 	for (i = 1; i < HPD_NUM_PINS; i++) {
 
 		if (!(hpd[i] & hotplug_trigger) ||
@@ -911,10 +909,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 		}
 	}
 
-	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-
 	if (storm_detected)
 		dev_priv->display.hpd_irq_setup(dev);
+	spin_unlock(&dev_priv->irq_lock);
 
 	queue_work(dev_priv->wq,
 		   &dev_priv->hotplug_work);
@@ -3327,6 +3324,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
 	struct intel_encoder *intel_encoder;
 	u32 hotplug_en;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if (I915_HAS_HOTPLUG(dev)) {
 		hotplug_en = I915_READ(PORT_HOTPLUG_EN);
 		hotplug_en &= ~HOTPLUG_INT_EN_MASK;
@@ -3610,6 +3609,7 @@ void intel_hpd_init(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct drm_connector *connector;
+	unsigned long irqflags;
 	int i;
 
 	for (i = 1; i < HPD_NUM_PINS; i++) {
@@ -3622,6 +3622,11 @@ void intel_hpd_init(struct drm_device *dev)
 		if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
 			connector->polled = DRM_CONNECTOR_POLL_HPD;
 	}
+
+	/* Interrup setup is already guaranteed to be single-threaded, this is
+	 * just to make the assert_spin_locked checks happy. */
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	if (dev_priv->display.hpd_irq_setup)
 		dev_priv->display.hpd_irq_setup(dev);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 09/24] drm/i915: extract ibx_display_interrupt_update
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (7 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 08/24] " Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-25 12:27   ` [PATCH] " Daniel Vetter
  2013-06-12 11:37 ` [PATCH 10/24] drm/i915: remove SERR_INT clearing in the postinstall hook Daniel Vetter
                   ` (14 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

This way all changes to SDEIMR all go through the same function, with
the exception of the (single-threaded) setup/teardown code.

For paranoia again add an assert_spin_locked.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 42 +++++++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 95e15cd..c2b4b09 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -177,6 +177,20 @@ static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
 	}
 }
 
+static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
+					 uint32_t interrupt_mask,
+					 uint32_t enabled_irq_mask)
+{
+	uint32_t sdeimr = I915_READ(SDEIMR);
+	sdeimr &= ~interrupt_mask;
+	sdeimr |= ~enabled_irq_mask;
+
+	assert_spin_locked(&dev_priv->irq_lock);
+
+	I915_WRITE(SDEIMR, sdeimr);
+	POSTING_READ(SDEIMR);
+}
+
 static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
 					    bool enable)
 {
@@ -185,12 +199,8 @@ static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
 	uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
 						SDE_TRANSB_FIFO_UNDER;
 
-	if (enable)
-		I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~bit);
-	else
-		I915_WRITE(SDEIMR, I915_READ(SDEIMR) | bit);
-
-	POSTING_READ(SDEIMR);
+	ibx_display_interrupt_update(dev_priv, bit,
+				     enable ? bit : 0);
 }
 
 static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
@@ -206,13 +216,10 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
 		I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN |
 				     SERR_INT_TRANS_B_FIFO_UNDERRUN |
 				     SERR_INT_TRANS_C_FIFO_UNDERRUN);
-
-		I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~SDE_ERROR_CPT);
-	} else {
-		I915_WRITE(SDEIMR, I915_READ(SDEIMR) | SDE_ERROR_CPT);
 	}
 
-	POSTING_READ(SDEIMR);
+	ibx_display_interrupt_update(dev_priv, SDE_ERROR_CPT,
+				     enable ? SDE_ERROR_CPT : 0);
 }
 
 /**
@@ -2585,22 +2592,21 @@ static void ibx_hpd_irq_setup(struct drm_device *dev)
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct intel_encoder *intel_encoder;
-	u32 mask = ~I915_READ(SDEIMR);
-	u32 hotplug;
+	u32 hotplug_irqs, hotplug, enabled_irqs = 0;
 
 	if (HAS_PCH_IBX(dev)) {
-		mask &= ~SDE_HOTPLUG_MASK;
+		hotplug_irqs = SDE_HOTPLUG_MASK;
 		list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
 			if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
-				mask |= hpd_ibx[intel_encoder->hpd_pin];
+				enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin];
 	} else {
-		mask &= ~SDE_HOTPLUG_MASK_CPT;
+		hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
 		list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
 			if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
-				mask |= hpd_cpt[intel_encoder->hpd_pin];
+				enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin];
 	}
 
-	I915_WRITE(SDEIMR, ~mask);
+	ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
 
 	/*
 	 * Enable digital hotplug on the PCH, and configure the DP short pulse
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 10/24] drm/i915: remove SERR_INT clearing in the postinstall hook
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (8 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 09/24] drm/i915: extract ibx_display_interrupt_update Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-27 19:34   ` Paulo Zanoni
  2013-06-12 11:37 ` [PATCH 11/24] drm/i915: improve SERR_INT clearing for fifo underrun reporting Daniel Vetter
                   ` (13 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

The preinstallhook is supposed to clear all interrupts. Doing it
again in the postinstall hook has the risk that we're eating
an interrupt source from the handler. If that happens too often,
the kernel will disable our interrupt handler.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index c2b4b09..685ad84 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2635,8 +2635,6 @@ static void ibx_irq_postinstall(struct drm_device *dev)
 		       SDE_TRANSA_FIFO_UNDER | SDE_POISON;
 	} else {
 		mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
-
-		I915_WRITE(SERR_INT, I915_READ(SERR_INT));
 	}
 
 	I915_WRITE(SDEIIR, I915_READ(SDEIIR));
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 11/24] drm/i915: improve SERR_INT clearing for fifo underrun reporting
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (9 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 10/24] drm/i915: remove SERR_INT clearing in the postinstall hook Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-27 20:19   ` Paulo Zanoni
  2013-06-12 11:37 ` [PATCH 12/24] drm/i915: improve GEN7_ERR_INT " Daniel Vetter
                   ` (12 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

The current code won't report any fifo underruns on cpt if just one
pipe has fifo underrun reporting disabled. We can't enable the
interrupts, but we can still check the per-transcoder bits and so
report the underrun delayed if:
- We always clear the transcoder's bit (and none of the other bits)
  when enabling.
- We check the transcoder's bit after disabling (to avoid racing with
  the interrupt handler).

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 15 +++++++++++----
 drivers/gpu/drm/i915/i915_reg.h |  1 +
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 685ad84..8627043 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -210,16 +210,23 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (enable) {
+		I915_WRITE(SERR_INT,
+			   SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
+
 		if (!cpt_can_enable_serr_int(dev))
 			return;
-
-		I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN |
-				     SERR_INT_TRANS_B_FIFO_UNDERRUN |
-				     SERR_INT_TRANS_C_FIFO_UNDERRUN);
 	}
 
 	ibx_display_interrupt_update(dev_priv, SDE_ERROR_CPT,
 				     enable ? SDE_ERROR_CPT : 0);
+
+	if (!enable) {
+		uint32_t tmp = I915_READ(SERR_INT);
+
+		if (tmp & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder))
+			DRM_DEBUG_KMS("uncleared pch fifo underrun on pipe %i\n",
+				      pch_transcoder);
+	}
 }
 
 /**
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index b1fdca9..86e3987 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3880,6 +3880,7 @@
 #define  SERR_INT_TRANS_C_FIFO_UNDERRUN	(1<<6)
 #define  SERR_INT_TRANS_B_FIFO_UNDERRUN	(1<<3)
 #define  SERR_INT_TRANS_A_FIFO_UNDERRUN	(1<<0)
+#define  SERR_INT_TRANS_FIFO_UNDERRUN(pipe)	(1<< (pipe*3))
 
 /* digital port hotplug */
 #define PCH_PORT_HOTPLUG        0xc4030		/* SHOTPLUG_CTL */
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 12/24] drm/i915: improve GEN7_ERR_INT clearing for fifo underrun reporting
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (10 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 11/24] drm/i915: improve SERR_INT clearing for fifo underrun reporting Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 11:37 ` [PATCH 13/24] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns Daniel Vetter
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Same treatment as for SERR_INT: If we clear only the bit for the pipe
we're enabling (but unconditionally) then we can always check for
possible underruns after having disabled the interrupt. That way pipe
underruns won't be lost, but at worst only get reported in a delayed
fashion.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 14 ++++++++------
 drivers/gpu/drm/i915/i915_reg.h |  1 +
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 8627043..bb26555 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -159,21 +159,23 @@ static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
 }
 
 static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
-						  bool enable)
+						  enum pipe pipe, bool enable)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (enable) {
+		I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
+
 		if (!ivb_can_enable_err_int(dev))
 			return;
 
-		I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN_A |
-					 ERR_INT_FIFO_UNDERRUN_B |
-					 ERR_INT_FIFO_UNDERRUN_C);
-
 		ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
 	} else {
 		ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+
+		if (I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe))
+			DRM_DEBUG_KMS("uncleared fifo underrun on pipe %i\n",
+				      pipe);
 	}
 }
 
@@ -264,7 +266,7 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
 	if (IS_GEN5(dev) || IS_GEN6(dev))
 		ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
 	else if (IS_GEN7(dev))
-		ivybridge_set_fifo_underrun_reporting(dev, enable);
+		ivybridge_set_fifo_underrun_reporting(dev, pipe, enable);
 
 done:
 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 86e3987..ec71b35 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -680,6 +680,7 @@
 #define   ERR_INT_FIFO_UNDERRUN_C	(1<<6)
 #define   ERR_INT_FIFO_UNDERRUN_B	(1<<3)
 #define   ERR_INT_FIFO_UNDERRUN_A	(1<<0)
+#define   ERR_INT_FIFO_UNDERRUN(pipe)	(1<< (pipe*3))
 
 #define FPGA_DBG		0x42300
 #define   FPGA_DBG_RM_NOCLAIM	(1<<31)
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 13/24] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (11 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 12/24] drm/i915: improve GEN7_ERR_INT " Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 13:04   ` Paulo Zanoni
  2013-06-12 11:37 ` [PATCH 14/24] drm/i915: irq handlers don't need interrupt-safe spinlocks Daniel Vetter
                   ` (10 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

It's racy: There's no guarantee that we won't walk this code (due to a
pch fifo underrun interrupt) while someone is changing the pointers
around.

The only reason we do this is to use the righ crtc for the pch fifo
underrun accounting. But we never expose this to userspace, so
essentially no one really cares if we use the "wrong" crtc.

So let's just rip it out.

With this patch fifo underrun code will always use crtc A for tracking
underruns on the (only) pch transcoder on LPT.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 33 +++++++--------------------------
 1 file changed, 7 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index bb26555..b98ea4e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -193,13 +193,13 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
 	POSTING_READ(SDEIMR);
 }
 
-static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
+static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
+					    enum transcoder pch_transcoder,
 					    bool enable)
 {
-	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
-						SDE_TRANSB_FIFO_UNDER;
+	uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
+		       SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
 
 	ibx_display_interrupt_update(dev_priv, bit,
 				     enable ? bit : 0);
@@ -292,30 +292,11 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
 					   bool enable)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	enum pipe p;
-	struct drm_crtc *crtc;
-	struct intel_crtc *intel_crtc;
+	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	unsigned long flags;
 	bool ret;
 
-	if (HAS_PCH_LPT(dev)) {
-		crtc = NULL;
-		for_each_pipe(p) {
-			struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p];
-			if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) {
-				crtc = c;
-				break;
-			}
-		}
-		if (!crtc) {
-			DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n");
-			return false;
-		}
-	} else {
-		crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
-	}
-	intel_crtc = to_intel_crtc(crtc);
-
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
 
 	ret = !intel_crtc->pch_fifo_underrun_disabled;
@@ -326,7 +307,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
 	intel_crtc->pch_fifo_underrun_disabled = !enable;
 
 	if (HAS_PCH_IBX(dev))
-		ibx_set_fifo_underrun_reporting(intel_crtc, enable);
+		ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
 	else
 		cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 14/24] drm/i915: irq handlers don't need interrupt-safe spinlocks
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (12 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 13/24] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-25 12:27   ` [PATCH] " Daniel Vetter
  2013-06-12 11:37 ` [PATCH 15/24] drm/i915: streamline hsw_pm_irq_handler Daniel Vetter
                   ` (9 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Since we only have one interrupt handler and interrupt handlers are
non-reentrant.

To drive the point really home give them all an _irq_handler suffix.

This is a tiny micro-optimization but even more important it makes it
clearer what locking we actually need. And in case someone screws this
up: lockdep will catch hardirq vs. other context deadlocks.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++++-----------------------
 1 file changed, 17 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b98ea4e..8bba0c5 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -633,14 +633,13 @@ static void i915_hotplug_work_func(struct work_struct *work)
 		drm_kms_helper_hotplug_event(dev);
 }
 
-static void ironlake_handle_rps_change(struct drm_device *dev)
+static void ironlake_rps_change_irq_handler(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 busy_up, busy_down, max_avg, min_avg;
 	u8 new_delay;
-	unsigned long flags;
 
-	spin_lock_irqsave(&mchdev_lock, flags);
+	spin_lock(&mchdev_lock);
 
 	I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
 
@@ -668,7 +667,7 @@ static void ironlake_handle_rps_change(struct drm_device *dev)
 	if (ironlake_set_drps(dev, new_delay))
 		dev_priv->ips.cur_delay = new_delay;
 
-	spin_unlock_irqrestore(&mchdev_lock, flags);
+	spin_unlock(&mchdev_lock);
 
 	return;
 }
@@ -804,18 +803,17 @@ static void ivybridge_parity_work(struct work_struct *work)
 	kfree(parity_event[1]);
 }
 
-static void ivybridge_handle_parity_error(struct drm_device *dev)
+static void ivybridge_parity_error_irq_handler(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	unsigned long flags;
 
 	if (!HAS_L3_GPU_CACHE(dev))
 		return;
 
-	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	spin_lock(&dev_priv->irq_lock);
 	dev_priv->gt_irq_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+	spin_unlock(&dev_priv->irq_lock);
 
 	queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
 }
@@ -845,11 +843,9 @@ static void snb_gt_irq_handler(struct drm_device *dev,
 }
 
 /* Legacy way of handling PM interrupts */
-static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
-				u32 pm_iir)
+static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv,
+				 u32 pm_iir)
 {
-	unsigned long flags;
-
 	/*
 	 * IIR bits should never already be set because IMR should
 	 * prevent an interrupt from being shown in IIR. The warning
@@ -860,11 +856,11 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
 	 * The mask bit in IMR is cleared by dev_priv->rps.work.
 	 */
 
-	spin_lock_irqsave(&dev_priv->rps.lock, flags);
+	spin_lock(&dev_priv->rps.lock);
 	dev_priv->rps.pm_iir |= pm_iir;
 	I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
 	POSTING_READ(GEN6_PMIMR);
-	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+	spin_unlock(&dev_priv->rps.lock);
 
 	queue_work(dev_priv->wq, &dev_priv->rps.work);
 }
@@ -928,7 +924,7 @@ static void dp_aux_irq_handler(struct drm_device *dev)
 	wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
-/* Unlike gen6_queue_rps_work() from which this function is originally derived,
+/* Unlike gen6_rps_irq_handler() from which this function is originally derived,
  * we must be able to deal with other PM interrupts. This is complicated because
  * of the way in which we use the masks to defer the RPS work (which for
  * posterity is necessary because of forcewake).
@@ -936,9 +932,7 @@ static void dp_aux_irq_handler(struct drm_device *dev)
 static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
 			       u32 pm_iir)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_priv->rps.lock, flags);
+	spin_lock(&dev_priv->rps.lock);
 	dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
 	if (dev_priv->rps.pm_iir) {
 		I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
@@ -947,7 +941,7 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
 		/* TODO: if queue_work is slow, move it out of the spinlock */
 		queue_work(dev_priv->wq, &dev_priv->rps.work);
 	}
-	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+	spin_unlock(&dev_priv->rps.lock);
 
 	if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
 		if (pm_iir & PM_VEBOX_USER_INTERRUPT)
@@ -1029,7 +1023,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 			gmbus_irq_handler(dev);
 
 		if (pm_iir & GEN6_PM_RPS_EVENTS)
-			gen6_queue_rps_work(dev_priv, pm_iir);
+			gen6_rps_irq_handler(dev_priv, pm_iir);
 
 		I915_WRITE(GTIIR, gt_iir);
 		I915_WRITE(GEN6_PMIIR, pm_iir);
@@ -1267,7 +1261,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 		if (IS_HASWELL(dev))
 			hsw_pm_irq_handler(dev_priv, pm_iir);
 		else if (pm_iir & GEN6_PM_RPS_EVENTS)
-			gen6_queue_rps_work(dev_priv, pm_iir);
+			gen6_rps_irq_handler(dev_priv, pm_iir);
 		I915_WRITE(GEN6_PMIIR, pm_iir);
 		ret = IRQ_HANDLED;
 	}
@@ -1383,10 +1377,10 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 	}
 
 	if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT)
-		ironlake_handle_rps_change(dev);
+		ironlake_rps_change_irq_handler(dev);
 
 	if (IS_GEN6(dev) && pm_iir & GEN6_PM_RPS_EVENTS)
-		gen6_queue_rps_work(dev_priv, pm_iir);
+		gen6_rps_irq_handler(dev_priv, pm_iir);
 
 	I915_WRITE(GTIIR, gt_iir);
 	I915_WRITE(DEIIR, de_iir);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 15/24] drm/i915: streamline hsw_pm_irq_handler
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (13 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 14/24] drm/i915: irq handlers don't need interrupt-safe spinlocks Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-25 12:28   ` [PATCH] " Daniel Vetter
  2013-06-12 11:37 ` [PATCH 16/24] drm/i915: queue work outside spinlock in hsw_pm_irq_handler Daniel Vetter
                   ` (8 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

The if (pm_iir & ~GEN6_PM_RPS_EVENTS) check was redunandant. Otoh
adding a check for rps events allows us to avoid the spinlock grabbing
for VECS interrupts.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 8bba0c5..29d4c9f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -839,7 +839,7 @@ static void snb_gt_irq_handler(struct drm_device *dev,
 	}
 
 	if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
-		ivybridge_handle_parity_error(dev);
+		ivybridge_parity_error_irq_handler(dev);
 }
 
 /* Legacy way of handling PM interrupts */
@@ -932,25 +932,23 @@ static void dp_aux_irq_handler(struct drm_device *dev)
 static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
 			       u32 pm_iir)
 {
-	spin_lock(&dev_priv->rps.lock);
-	dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
-	if (dev_priv->rps.pm_iir) {
+	if (pm_iir & GEN6_PM_RPS_EVENTS) {
+		spin_lock(&dev_priv->rps.lock);
+		dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
 		I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
 		/* never want to mask useful interrupts. (also posting read) */
 		WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
 		/* TODO: if queue_work is slow, move it out of the spinlock */
 		queue_work(dev_priv->wq, &dev_priv->rps.work);
+		spin_unlock(&dev_priv->rps.lock);
 	}
-	spin_unlock(&dev_priv->rps.lock);
 
-	if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
-		if (pm_iir & PM_VEBOX_USER_INTERRUPT)
-			notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
+	if (pm_iir & PM_VEBOX_USER_INTERRUPT)
+		notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
 
-		if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
-			DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
-			i915_handle_error(dev_priv->dev, false);
-		}
+	if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
+		DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
+		i915_handle_error(dev_priv->dev, false);
 	}
 }
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 16/24] drm/i915: queue work outside spinlock in hsw_pm_irq_handler
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (14 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 15/24] drm/i915: streamline hsw_pm_irq_handler Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 11:37 ` [PATCH 17/24] drm/i915: kill dev_priv->rps.lock Daniel Vetter
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

And kill the comment about it. Queueing work is a barrier type event,
no amount of locking will help in ordering things (as long as we queue
the work after having updated all relevant data structures). Also, the
queue_work works itself as a sufficient memory barrier.

Again on the surface this is just a tiny micro-optimization to reduce
the hold-time of dev_priv->irq_lock. But the better reason is that it
reduces superficial locking and so makes it clearer what we actually
need for correctness.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 29d4c9f..752b98d 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -938,9 +938,9 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
 		I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
 		/* never want to mask useful interrupts. (also posting read) */
 		WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
-		/* TODO: if queue_work is slow, move it out of the spinlock */
-		queue_work(dev_priv->wq, &dev_priv->rps.work);
 		spin_unlock(&dev_priv->rps.lock);
+
+		queue_work(dev_priv->wq, &dev_priv->rps.work);
 	}
 
 	if (pm_iir & PM_VEBOX_USER_INTERRUPT)
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 17/24] drm/i915: kill dev_priv->rps.lock
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (15 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 16/24] drm/i915: queue work outside spinlock in hsw_pm_irq_handler Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-28  3:35   ` Ben Widawsky
  2013-06-28  3:35   ` Ben Widawsky
  2013-06-12 11:37 ` [PATCH 18/24] drm/i915: unify ring irq refcounts (again) Daniel Vetter
                   ` (6 subsequent siblings)
  23 siblings, 2 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Now that the rps interrupt locking isn't clearly separated (at elast
conceptually) from all the other interrupt locking having a different
lock stopped making sense. With this we can (again) unifiy the
ringbuffer irq refcounts without causing a massive confusion, but
that's for the next patch.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_dma.c         |  1 -
 drivers/gpu/drm/i915/i915_drv.h         |  8 ++++----
 drivers/gpu/drm/i915/i915_irq.c         | 12 ++++++------
 drivers/gpu/drm/i915/intel_pm.c         | 16 ++++++++--------
 drivers/gpu/drm/i915/intel_ringbuffer.c |  8 ++++----
 drivers/gpu/drm/i915/intel_ringbuffer.h |  2 +-
 6 files changed, 23 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index b913b3d..14c3e9c 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1612,7 +1612,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
 	spin_lock_init(&dev_priv->irq_lock);
 	spin_lock_init(&dev_priv->gpu_error.lock);
-	spin_lock_init(&dev_priv->rps.lock);
 	spin_lock_init(&dev_priv->backlight.lock);
 	mutex_init(&dev_priv->dpio_lock);
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 07954b2..42d1363 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -691,12 +691,12 @@ struct i915_suspend_saved_registers {
 };
 
 struct intel_gen6_power_mgmt {
+	/* work and pm_iir are protected by dev_priv->irq_lock */
 	struct work_struct work;
-	struct delayed_work vlv_work;
 	u32 pm_iir;
-	/* lock - irqsave spinlock that protectects the work_struct and
-	 * pm_iir. */
-	spinlock_t lock;
+
+	/* On vlv we need to manually drop to Vmin with a delayed work. */
+	struct delayed_work vlv_work;
 
 	/* The below variables an all the rps hw state are protected by
 	 * dev->struct mutext. */
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 752b98d..cd7135d 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -696,13 +696,13 @@ static void gen6_pm_rps_work(struct work_struct *work)
 	u32 pm_iir, pm_imr;
 	u8 new_delay;
 
-	spin_lock_irq(&dev_priv->rps.lock);
+	spin_lock_irq(&dev_priv->irq_lock);
 	pm_iir = dev_priv->rps.pm_iir;
 	dev_priv->rps.pm_iir = 0;
 	pm_imr = I915_READ(GEN6_PMIMR);
 	/* Make sure not to corrupt PMIMR state used by ringbuffer code */
 	I915_WRITE(GEN6_PMIMR, pm_imr & ~GEN6_PM_RPS_EVENTS);
-	spin_unlock_irq(&dev_priv->rps.lock);
+	spin_unlock_irq(&dev_priv->irq_lock);
 
 	if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0)
 		return;
@@ -856,11 +856,11 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv,
 	 * The mask bit in IMR is cleared by dev_priv->rps.work.
 	 */
 
-	spin_lock(&dev_priv->rps.lock);
+	spin_lock(&dev_priv->irq_lock);
 	dev_priv->rps.pm_iir |= pm_iir;
 	I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
 	POSTING_READ(GEN6_PMIMR);
-	spin_unlock(&dev_priv->rps.lock);
+	spin_unlock(&dev_priv->irq_lock);
 
 	queue_work(dev_priv->wq, &dev_priv->rps.work);
 }
@@ -933,12 +933,12 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
 			       u32 pm_iir)
 {
 	if (pm_iir & GEN6_PM_RPS_EVENTS) {
-		spin_lock(&dev_priv->rps.lock);
+		spin_lock(&dev_priv->irq_lock);
 		dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
 		I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
 		/* never want to mask useful interrupts. (also posting read) */
 		WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
-		spin_unlock(&dev_priv->rps.lock);
+		spin_unlock(&dev_priv->irq_lock);
 
 		queue_work(dev_priv->wq, &dev_priv->rps.work);
 	}
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index adc44e4..6a5cfb5 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3128,9 +3128,9 @@ static void gen6_disable_rps(struct drm_device *dev)
 	 * register (PMIMR) to mask PM interrupts. The only risk is in leaving
 	 * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
 
-	spin_lock_irq(&dev_priv->rps.lock);
+	spin_lock_irq(&dev_priv->irq_lock);
 	dev_priv->rps.pm_iir = 0;
-	spin_unlock_irq(&dev_priv->rps.lock);
+	spin_unlock_irq(&dev_priv->irq_lock);
 
 	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
 }
@@ -3147,9 +3147,9 @@ static void valleyview_disable_rps(struct drm_device *dev)
 	 * register (PMIMR) to mask PM interrupts. The only risk is in leaving
 	 * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
 
-	spin_lock_irq(&dev_priv->rps.lock);
+	spin_lock_irq(&dev_priv->irq_lock);
 	dev_priv->rps.pm_iir = 0;
-	spin_unlock_irq(&dev_priv->rps.lock);
+	spin_unlock_irq(&dev_priv->irq_lock);
 
 	I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
 
@@ -3314,13 +3314,13 @@ static void gen6_enable_rps(struct drm_device *dev)
 
 	/* requires MSI enabled */
 	I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS);
-	spin_lock_irq(&dev_priv->rps.lock);
+	spin_lock_irq(&dev_priv->irq_lock);
 	/* FIXME: Our interrupt enabling sequence is bonghits.
 	 * dev_priv->rps.pm_iir really should be 0 here. */
 	dev_priv->rps.pm_iir = 0;
 	I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
 	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
-	spin_unlock_irq(&dev_priv->rps.lock);
+	spin_unlock_irq(&dev_priv->irq_lock);
 	/* unmask all PM interrupts */
 	I915_WRITE(GEN6_PMINTRMSK, 0);
 
@@ -3585,10 +3585,10 @@ static void valleyview_enable_rps(struct drm_device *dev)
 
 	/* requires MSI enabled */
 	I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS);
-	spin_lock_irq(&dev_priv->rps.lock);
+	spin_lock_irq(&dev_priv->irq_lock);
 	WARN_ON(dev_priv->rps.pm_iir != 0);
 	I915_WRITE(GEN6_PMIMR, 0);
-	spin_unlock_irq(&dev_priv->rps.lock);
+	spin_unlock_irq(&dev_priv->irq_lock);
 	/* enable all PM interrupts */
 	I915_WRITE(GEN6_PMINTRMSK, 0);
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 1ef081c..a7c9934 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1053,14 +1053,14 @@ hsw_vebox_get_irq(struct intel_ring_buffer *ring)
 	if (!dev->irq_enabled)
 		return false;
 
-	spin_lock_irqsave(&dev_priv->rps.lock, flags);
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
 	if (ring->irq_refcount.pm++ == 0) {
 		u32 pm_imr = I915_READ(GEN6_PMIMR);
 		I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
 		I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
 		POSTING_READ(GEN6_PMIMR);
 	}
-	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 
 	return true;
 }
@@ -1075,14 +1075,14 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring)
 	if (!dev->irq_enabled)
 		return;
 
-	spin_lock_irqsave(&dev_priv->rps.lock, flags);
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
 	if (--ring->irq_refcount.pm == 0) {
 		u32 pm_imr = I915_READ(GEN6_PMIMR);
 		I915_WRITE_IMR(ring, ~0);
 		I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
 		POSTING_READ(GEN6_PMIMR);
 	}
-	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 }
 
 static int
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index efc403d..f960805 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -76,7 +76,7 @@ struct  intel_ring_buffer {
 
 	struct {
 		u32	gt; /*  protected by dev_priv->irq_lock */
-		u32	pm; /*  protected by dev_priv->rps.lock (sucks) */
+		u32	pm; /*  protected by dev_priv->irq_lock */
 	} irq_refcount;
 	u32		irq_enable_mask;	/* bitmask to enable ring interrupt */
 	u32		trace_irq_seqno;
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 18/24] drm/i915: unify ring irq refcounts (again)
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (16 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 17/24] drm/i915: kill dev_priv->rps.lock Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-28 17:24   ` Ben Widawsky
  2013-06-12 11:37 ` [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT Daniel Vetter
                   ` (5 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

With the simplified locking there's no reason any more to keep the
refcounts seperate.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/intel_ringbuffer.c | 20 ++++++++++----------
 drivers/gpu/drm/i915/intel_ringbuffer.h |  5 +----
 2 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index a7c9934..b75e9d0 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -819,7 +819,7 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring)
 		return false;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (ring->irq_refcount.gt++ == 0) {
+	if (ring->irq_refcount++ == 0) {
 		dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
 		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 		POSTING_READ(GTIMR);
@@ -837,7 +837,7 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring)
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (--ring->irq_refcount.gt == 0) {
+	if (--ring->irq_refcount == 0) {
 		dev_priv->gt_irq_mask |= ring->irq_enable_mask;
 		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 		POSTING_READ(GTIMR);
@@ -856,7 +856,7 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring)
 		return false;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (ring->irq_refcount.gt++ == 0) {
+	if (ring->irq_refcount++ == 0) {
 		dev_priv->irq_mask &= ~ring->irq_enable_mask;
 		I915_WRITE(IMR, dev_priv->irq_mask);
 		POSTING_READ(IMR);
@@ -874,7 +874,7 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring)
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (--ring->irq_refcount.gt == 0) {
+	if (--ring->irq_refcount == 0) {
 		dev_priv->irq_mask |= ring->irq_enable_mask;
 		I915_WRITE(IMR, dev_priv->irq_mask);
 		POSTING_READ(IMR);
@@ -893,7 +893,7 @@ i8xx_ring_get_irq(struct intel_ring_buffer *ring)
 		return false;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (ring->irq_refcount.gt++ == 0) {
+	if (ring->irq_refcount++ == 0) {
 		dev_priv->irq_mask &= ~ring->irq_enable_mask;
 		I915_WRITE16(IMR, dev_priv->irq_mask);
 		POSTING_READ16(IMR);
@@ -911,7 +911,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring)
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (--ring->irq_refcount.gt == 0) {
+	if (--ring->irq_refcount == 0) {
 		dev_priv->irq_mask |= ring->irq_enable_mask;
 		I915_WRITE16(IMR, dev_priv->irq_mask);
 		POSTING_READ16(IMR);
@@ -1004,7 +1004,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
 	gen6_gt_force_wake_get(dev_priv);
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (ring->irq_refcount.gt++ == 0) {
+	if (ring->irq_refcount++ == 0) {
 		if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
 			I915_WRITE_IMR(ring,
 				       ~(ring->irq_enable_mask |
@@ -1028,7 +1028,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (--ring->irq_refcount.gt == 0) {
+	if (--ring->irq_refcount == 0) {
 		if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
 			I915_WRITE_IMR(ring,
 				       ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
@@ -1054,7 +1054,7 @@ hsw_vebox_get_irq(struct intel_ring_buffer *ring)
 		return false;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (ring->irq_refcount.pm++ == 0) {
+	if (ring->irq_refcount++ == 0) {
 		u32 pm_imr = I915_READ(GEN6_PMIMR);
 		I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
 		I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
@@ -1076,7 +1076,7 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring)
 		return;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
-	if (--ring->irq_refcount.pm == 0) {
+	if (--ring->irq_refcount == 0) {
 		u32 pm_imr = I915_READ(GEN6_PMIMR);
 		I915_WRITE_IMR(ring, ~0);
 		I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index f960805..26e304c 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -74,10 +74,7 @@ struct  intel_ring_buffer {
 	 */
 	u32		last_retired_head;
 
-	struct {
-		u32	gt; /*  protected by dev_priv->irq_lock */
-		u32	pm; /*  protected by dev_priv->irq_lock */
-	} irq_refcount;
+	unsigned irq_refcount;
 	u32		irq_enable_mask;	/* bitmask to enable ring interrupt */
 	u32		trace_irq_seqno;
 	u32		sync_seqno[I915_NUM_RINGS-1];
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (17 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 18/24] drm/i915: unify ring irq refcounts (again) Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 17:13   ` Ben Widawsky
  2013-06-12 11:37 ` [PATCH 20/24] drm/i915: kill bogus GTIIR clearing in vlv_preinstall hook Daniel Vetter
                   ` (4 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter, Ben Widawsky

The code to handle it is broken - there's simply no code to clear CS
parser errors on gen5+. And behold, for all the other rings we also
don't enable it!

Leave the handling code itself in place just to be consistent with the
existing mess though. And in case someone feels like fixing it all up.

This has been errornously enabled in

commit 12638c57f31952127c734c26315e1348fa1334c2
Author: Ben Widawsky <ben@bwidawsk.net>
Date:   Tue May 28 19:22:31 2013 -0700

    drm/i915: Enable vebox interrupts

Cc: Damien Lespiau <damien.lespiau@intel.com>
Cc: Ben Widawsky <ben@bwidawsk.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c         | 3 +--
 drivers/gpu/drm/i915/intel_ringbuffer.c | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index cd7135d..293ee68 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2715,8 +2715,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
 
 	I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
 	if (HAS_VEBOX(dev))
-		pm_irqs |= PM_VEBOX_USER_INTERRUPT |
-			PM_VEBOX_CS_ERROR_INTERRUPT;
+		pm_irqs |= PM_VEBOX_USER_INTERRUPT;
 
 	/* Our enable/disable rps functions may touch these registers so
 	 * make sure to set a known state for only the non-RPS bits.
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index b75e9d0..a86d5d6 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1998,8 +1998,7 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev)
 	ring->add_request = gen6_add_request;
 	ring->get_seqno = gen6_ring_get_seqno;
 	ring->set_seqno = ring_set_seqno;
-	ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT |
-		PM_VEBOX_CS_ERROR_INTERRUPT;
+	ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
 	ring->irq_get = hsw_vebox_get_irq;
 	ring->irq_put = hsw_vebox_put_irq;
 	ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 20/24] drm/i915: kill bogus GTIIR clearing in vlv_preinstall hook
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (18 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-28 17:01   ` Ben Widawsky
  2013-06-12 11:37 ` [PATCH 21/24] drm/i915: unify PM interrupt preinstall sequence Daniel Vetter
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Preinstall disables interrupts, we clear the status register in the
postinstall hook before we actually enable interrupt sources.

Also add a comment for the curios ring IMR masking, it doesn't
seem to be required on any other platform.

We seem to have some room for common gt_preinstall/postinstall hooks.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 293ee68..b680e1c 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2546,13 +2546,12 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
 
 	/* VLV magic */
 	I915_WRITE(VLV_IMR, 0);
+	/* Do we really need to clear ring masks for vlv? */
 	I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
 	I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0);
 	I915_WRITE(RING_IMR(BLT_RING_BASE), 0);
 
 	/* and GT */
-	I915_WRITE(GTIIR, I915_READ(GTIIR));
-	I915_WRITE(GTIIR, I915_READ(GTIIR));
 	I915_WRITE(GTIMR, 0xffffffff);
 	I915_WRITE(GTIER, 0x0);
 	POSTING_READ(GTIER);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 21/24] drm/i915: unify PM interrupt preinstall sequence
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (19 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 20/24] drm/i915: kill bogus GTIIR clearing in vlv_preinstall hook Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-28 17:26   ` Ben Widawsky
  2013-06-12 11:37 ` [PATCH 22/24] drm/i915: unify GT/PM irq postinstall code Daniel Vetter
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Since the addition of VECS we have a slightly different enable
sequence for PM interrupts on ivb/hsw vs snb and vlv. Usually that
will end up in hard to track down surprises.

Hence unifiy things and since we have copies of this code in 3 places
now, extract it into its own little helper.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++++-----------------------
 1 file changed, 17 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b680e1c..954d8f8 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2486,17 +2486,9 @@ static void ibx_irq_preinstall(struct drm_device *dev)
 	POSTING_READ(SDEIER);
 }
 
-/* drm_dma.h hooks
-*/
-static void ironlake_irq_preinstall(struct drm_device *dev)
+static void gen5_gt_irq_preinstall(struct drm_device *dev)
 {
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-
-	atomic_set(&dev_priv->irq_received, 0);
-
-	I915_WRITE(HWSTAM, 0xeffe);
-
-	/* XXX hotplug from PCH */
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	I915_WRITE(DEIMR, 0xffffffff);
 	I915_WRITE(DEIER, 0x0);
@@ -2506,6 +2498,19 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
 	I915_WRITE(GTIMR, 0xffffffff);
 	I915_WRITE(GTIER, 0x0);
 	POSTING_READ(GTIER);
+}
+
+/* drm_dma.h hooks
+*/
+static void ironlake_irq_preinstall(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+	atomic_set(&dev_priv->irq_received, 0);
+
+	I915_WRITE(HWSTAM, 0xeffe);
+
+	gen5_gt_irq_preinstall(dev);
 
 	ibx_irq_preinstall(dev);
 }
@@ -2524,15 +2529,7 @@ static void ivybridge_irq_preinstall(struct drm_device *dev)
 	I915_WRITE(DEIER, 0x0);
 	POSTING_READ(DEIER);
 
-	/* and GT */
-	I915_WRITE(GTIMR, 0xffffffff);
-	I915_WRITE(GTIER, 0x0);
-	POSTING_READ(GTIER);
-
-	/* Power management */
-	I915_WRITE(GEN6_PMIMR, 0xffffffff);
-	I915_WRITE(GEN6_PMIER, 0x0);
-	POSTING_READ(GEN6_PMIER);
+	gen5_gt_irq_preinstall(dev);
 
 	ibx_irq_preinstall(dev);
 }
@@ -2551,10 +2548,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
 	I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0);
 	I915_WRITE(RING_IMR(BLT_RING_BASE), 0);
 
-	/* and GT */
-	I915_WRITE(GTIMR, 0xffffffff);
-	I915_WRITE(GTIER, 0x0);
-	POSTING_READ(GTIER);
+	gen5_gt_irq_preinstall(dev);
 
 	I915_WRITE(DPINVGTT, 0xff);
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 22/24] drm/i915: unify GT/PM irq postinstall code
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (20 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 21/24] drm/i915: unify PM interrupt preinstall sequence Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 11:37 ` [PATCH 23/24] drm/i915: extract rps interrupt enable/disable helpers Daniel Vetter
  2013-06-12 11:37 ` [PATCH 24/24] drm/i915: simplify rps interrupt enabling/disabling sequence Daniel Vetter
  23 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Again extract a common helper. For the postinstall hook things are a
bit more complicated since we have more cases on ilk-hsw/vlv here.

But since vlv was clearly broken by failing to initialize
dev_priv->gt_irq_mask correclty (mayb that explains the strange
RING_IMR clearing in the preinstall hook?) clearly justified the
shared code.

Also kill the PMIER setting in the async rps enable work. I should
have been save, but also clearly looked rather fragile.

With this we now have the usual interrupt register sequence for GT/PM
irq registers:

- IER is setup once with all the interrupts we ever need in the
  postinstall hook and never touched again. Exceptions are SDEIER,
  which is touched in the preinstall hook (when the irq handler isn't
  enabled) and then only from the irq handler. And DEIER/VLV_IER with
  is used in the irq handler but also written to once in the
  postinstall hook. But since that write is essentially what enables
  the interrupt and we should always have MSI interrupts we should be
  save. In case we ever have non-MSI interrupts we'd be screwed.

- IIR is cleared in the postinstall hook before we enable/unmask the
  respective interrupt sources. Hence we can't steal an interrupt
  event an accidentally trigger the spurious interrupt logic in the
  core kernel.

- IMR regs are (usually) all masked off. Those are the only regs
  changed at runtime, which is all protected by dev_priv->irq_lock.

This unification also kills the cargo-culted read-modify-write PM
register setup for VECS. Interrupt setup is done without userspace
being able to interfere, so we better know what values we want to put
into those registers. RMW cycles otoh are really good at papering over
races, until stuff magically blows up and no one has a clue why.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 91 +++++++++++++++++++----------------------
 drivers/gpu/drm/i915/intel_pm.c |  4 --
 2 files changed, 41 insertions(+), 54 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 954d8f8..1fb49f7 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2616,6 +2616,44 @@ static void ibx_irq_postinstall(struct drm_device *dev)
 	I915_WRITE(SDEIMR, ~mask);
 }
 
+static void gen5_gt_irq_postinstall(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 pm_irqs, gt_irqs;
+
+	pm_irqs = gt_irqs = 0;
+
+	dev_priv->gt_irq_mask = ~0;
+	if (HAS_L3_GPU_CACHE(dev)) {
+		dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+		gt_irqs |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+	}
+
+	gt_irqs |= GT_RENDER_USER_INTERRUPT;
+	if (IS_GEN5(dev)) {
+		gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT |
+			   ILK_BSD_USER_INTERRUPT;
+	} else {
+		gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
+	}
+
+	I915_WRITE(GTIIR, I915_READ(GTIIR));
+	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+	I915_WRITE(GTIER, gt_irqs);
+	POSTING_READ(GTIER);
+
+	if (HAS_VEBOX(dev))
+		pm_irqs |= PM_VEBOX_USER_INTERRUPT;
+	if (INTEL_INFO(dev)->gen >= 6)
+		pm_irqs |= GEN6_PM_RPS_EVENTS;
+
+	I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+	I915_WRITE(GEN6_PMIMR, 0xffffffff);
+	I915_WRITE(GEN6_PMIER, pm_irqs);
+	POSTING_READ(GEN6_PMIER);
+
+}
+
 static int ironlake_irq_postinstall(struct drm_device *dev)
 {
 	unsigned long irqflags;
@@ -2626,7 +2664,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 			   DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
 			   DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN |
 			   DE_PIPEA_FIFO_UNDERRUN | DE_POISON;
-	u32 gt_irqs;
 
 	dev_priv->irq_mask = ~display_mask;
 
@@ -2637,21 +2674,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 			  DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT);
 	POSTING_READ(DEIER);
 
-	dev_priv->gt_irq_mask = ~0;
-
-	I915_WRITE(GTIIR, I915_READ(GTIIR));
-	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-
-	gt_irqs = GT_RENDER_USER_INTERRUPT;
-
-	if (IS_GEN6(dev))
-		gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
-	else
-		gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT |
-			   ILK_BSD_USER_INTERRUPT;
-
-	I915_WRITE(GTIER, gt_irqs);
-	POSTING_READ(GTIER);
+	gen5_gt_irq_postinstall(dev);
 
 	ibx_irq_postinstall(dev);
 
@@ -2680,8 +2703,6 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
 		DE_PLANEA_FLIP_DONE_IVB |
 		DE_AUX_CHANNEL_A_IVB |
 		DE_ERR_INT_IVB;
-	u32 pm_irqs = GEN6_PM_RPS_EVENTS;
-	u32 gt_irqs;
 
 	dev_priv->irq_mask = ~display_mask;
 
@@ -2696,30 +2717,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
 		   DE_PIPEA_VBLANK_IVB);
 	POSTING_READ(DEIER);
 
-	dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
-
-	I915_WRITE(GTIIR, I915_READ(GTIIR));
-	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-
-	gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
-		  GT_BLT_USER_INTERRUPT | GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
-	I915_WRITE(GTIER, gt_irqs);
-	POSTING_READ(GTIER);
-
-	I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
-	if (HAS_VEBOX(dev))
-		pm_irqs |= PM_VEBOX_USER_INTERRUPT;
-
-	/* Our enable/disable rps functions may touch these registers so
-	 * make sure to set a known state for only the non-RPS bits.
-	 * The RMW is extra paranoia since this should be called after being set
-	 * to a known state in preinstall.
-	 * */
-	I915_WRITE(GEN6_PMIMR,
-		   (I915_READ(GEN6_PMIMR) | ~GEN6_PM_RPS_EVENTS) & ~pm_irqs);
-	I915_WRITE(GEN6_PMIER,
-		   (I915_READ(GEN6_PMIER) & GEN6_PM_RPS_EVENTS) | pm_irqs);
-	POSTING_READ(GEN6_PMIER);
+	gen5_gt_irq_postinstall(dev);
 
 	ibx_irq_postinstall(dev);
 
@@ -2729,7 +2727,6 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
 static int valleyview_irq_postinstall(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	u32 gt_irqs;
 	u32 enable_mask;
 	u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
 	unsigned long irqflags;
@@ -2769,13 +2766,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 	I915_WRITE(VLV_IIR, 0xffffffff);
 	I915_WRITE(VLV_IIR, 0xffffffff);
 
-	I915_WRITE(GTIIR, I915_READ(GTIIR));
-	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-
-	gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
-		GT_BLT_USER_INTERRUPT;
-	I915_WRITE(GTIER, gt_irqs);
-	POSTING_READ(GTIER);
+	gen5_gt_irq_postinstall(dev);
 
 	/* ack & enable invalid PTE error interrupts */
 #if 0 /* FIXME: add support to irq handler for checking these bits */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 6a5cfb5..1f3dcdc 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3312,8 +3312,6 @@ static void gen6_enable_rps(struct drm_device *dev)
 
 	gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8);
 
-	/* requires MSI enabled */
-	I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS);
 	spin_lock_irq(&dev_priv->irq_lock);
 	/* FIXME: Our interrupt enabling sequence is bonghits.
 	 * dev_priv->rps.pm_iir really should be 0 here. */
@@ -3583,8 +3581,6 @@ static void valleyview_enable_rps(struct drm_device *dev)
 
 	valleyview_set_rps(dev_priv->dev, rpe);
 
-	/* requires MSI enabled */
-	I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS);
 	spin_lock_irq(&dev_priv->irq_lock);
 	WARN_ON(dev_priv->rps.pm_iir != 0);
 	I915_WRITE(GEN6_PMIMR, 0);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 23/24] drm/i915: extract rps interrupt enable/disable helpers
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (21 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 22/24] drm/i915: unify GT/PM irq postinstall code Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 11:37 ` [PATCH 24/24] drm/i915: simplify rps interrupt enabling/disabling sequence Daniel Vetter
  23 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

This just unifies the vlv code with the snb-hsw code which matched
exactly before the VECS enabling.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/intel_pm.c | 59 ++++++++++++++++++++---------------------
 1 file changed, 29 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 1f3dcdc..2fd67ec 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3114,13 +3114,10 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
 	trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val));
 }
 
-
-static void gen6_disable_rps(struct drm_device *dev)
+static void gen6_disable_rps_interrupts(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	I915_WRITE(GEN6_RC_CONTROL, 0);
-	I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
 	I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
 	I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) & ~GEN6_PM_RPS_EVENTS);
 	/* Complete PM interrupt masking here doesn't race with the rps work
@@ -3135,23 +3132,23 @@ static void gen6_disable_rps(struct drm_device *dev)
 	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
 }
 
-static void valleyview_disable_rps(struct drm_device *dev)
+static void gen6_disable_rps(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	I915_WRITE(GEN6_RC_CONTROL, 0);
-	I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
-	I915_WRITE(GEN6_PMIER, 0);
-	/* Complete PM interrupt masking here doesn't race with the rps work
-	 * item again unmasking PM interrupts because that is using a different
-	 * register (PMIMR) to mask PM interrupts. The only risk is in leaving
-	 * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
+	I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
 
-	spin_lock_irq(&dev_priv->irq_lock);
-	dev_priv->rps.pm_iir = 0;
-	spin_unlock_irq(&dev_priv->irq_lock);
+	gen6_disable_rps_interrupts(dev);
+}
+
+static void valleyview_disable_rps(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	I915_WRITE(GEN6_RC_CONTROL, 0);
 
-	I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+	gen6_disable_rps_interrupts(dev);
 
 	if (dev_priv->vlv_pctx) {
 		drm_gem_object_unreference(&dev_priv->vlv_pctx->base);
@@ -3184,6 +3181,21 @@ int intel_enable_rc6(const struct drm_device *dev)
 	return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
 }
 
+static void gen6_enable_rps_interrupts(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	spin_lock_irq(&dev_priv->irq_lock);
+	/* FIXME: Our interrupt enabling sequence is bonghits.
+	 * dev_priv->rps.pm_iir really should be 0 here. */
+	dev_priv->rps.pm_iir = 0;
+	I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
+	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
+	spin_unlock_irq(&dev_priv->irq_lock);
+	/* unmask all PM interrupts */
+	I915_WRITE(GEN6_PMINTRMSK, 0);
+}
+
 static void gen6_enable_rps(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3312,15 +3324,7 @@ static void gen6_enable_rps(struct drm_device *dev)
 
 	gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8);
 
-	spin_lock_irq(&dev_priv->irq_lock);
-	/* FIXME: Our interrupt enabling sequence is bonghits.
-	 * dev_priv->rps.pm_iir really should be 0 here. */
-	dev_priv->rps.pm_iir = 0;
-	I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
-	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
-	spin_unlock_irq(&dev_priv->irq_lock);
-	/* unmask all PM interrupts */
-	I915_WRITE(GEN6_PMINTRMSK, 0);
+	gen6_enable_rps_interrupts(dev);
 
 	rc6vids = 0;
 	ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
@@ -3581,12 +3585,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
 
 	valleyview_set_rps(dev_priv->dev, rpe);
 
-	spin_lock_irq(&dev_priv->irq_lock);
-	WARN_ON(dev_priv->rps.pm_iir != 0);
-	I915_WRITE(GEN6_PMIMR, 0);
-	spin_unlock_irq(&dev_priv->irq_lock);
-	/* enable all PM interrupts */
-	I915_WRITE(GEN6_PMINTRMSK, 0);
+	gen6_enable_rps_interrupts(dev);
 
 	gen6_gt_force_wake_put(dev_priv);
 }
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 24/24] drm/i915: simplify rps interrupt enabling/disabling sequence
  2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
                   ` (22 preceding siblings ...)
  2013-06-12 11:37 ` [PATCH 23/24] drm/i915: extract rps interrupt enable/disable helpers Daniel Vetter
@ 2013-06-12 11:37 ` Daniel Vetter
  2013-06-12 22:32   ` Ben Widawsky
  23 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 11:37 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter, Ben Widawsky

At the moment we have the following interrupt enabling sequence:
1. irq preinstall hook
2. enabling the interrupt handler and calling irq postinstall hook
3. enable rps interrupts from the async work

And the folliwing disable sequence:
1. disabling the interrupt handler and calling the uninstall hook
2. disabling the rps interrupt

Since the postinstall hook now always sets up PMIIR, PMIER and PMIMR
to known-good states there no way for an interrupt to sneak in in the
enable sequence, so we can reinstate the WARN lost in

commit eda63ffb906c2fb3b609a0e87aeb63c0f25b9e6b
Author: Ben Widawsky <ben@bwidawsk.net>
Date:   Tue May 28 19:22:26 2013 -0700

    drm/i915: Add PM regs to pre/post install

Note that there's some room for future cleanups since most of the
interrupt register clearing in the disable function is rather
redundant. But that's better done in follow-up patches, if at all.

Cc: Ben Widawsky <ben@bwidawsk.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/intel_pm.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 2fd67ec..6d13265 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3186,9 +3186,7 @@ static void gen6_enable_rps_interrupts(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	spin_lock_irq(&dev_priv->irq_lock);
-	/* FIXME: Our interrupt enabling sequence is bonghits.
-	 * dev_priv->rps.pm_iir really should be 0 here. */
-	dev_priv->rps.pm_iir = 0;
+	WARN_ON(dev_priv->rps.pm_iir);
 	I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
 	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
 	spin_unlock_irq(&dev_priv->irq_lock);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* Re: [PATCH 13/24] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns
  2013-06-12 11:37 ` [PATCH 13/24] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns Daniel Vetter
@ 2013-06-12 13:04   ` Paulo Zanoni
  2013-06-12 14:46     ` [PATCH] " Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-12 13:04 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

2013/6/12 Daniel Vetter <daniel.vetter@ffwll.ch>:
> It's racy: There's no guarantee that we won't walk this code (due to a
> pch fifo underrun interrupt) while someone is changing the pointers
> around.
>
> The only reason we do this is to use the righ crtc for the pch fifo
> underrun accounting. But we never expose this to userspace, so
> essentially no one really cares if we use the "wrong" crtc.
>
> So let's just rip it out.
>
> With this patch fifo underrun code will always use crtc A for tracking
> underruns on the (only) pch transcoder on LPT.

Please add a big comment in the source code explaining the hack and its reason.

>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 33 +++++++--------------------------
>  1 file changed, 7 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index bb26555..b98ea4e 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -193,13 +193,13 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
>         POSTING_READ(SDEIMR);
>  }
>
> -static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
> +static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
> +                                           enum transcoder pch_transcoder,
>                                             bool enable)
>  {
> -       struct drm_device *dev = crtc->base.dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> -       uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
> -                                               SDE_TRANSB_FIFO_UNDER;
> +       uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
> +                      SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
>
>         ibx_display_interrupt_update(dev_priv, bit,
>                                      enable ? bit : 0);
> @@ -292,30 +292,11 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
>                                            bool enable)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
> -       enum pipe p;
> -       struct drm_crtc *crtc;
> -       struct intel_crtc *intel_crtc;
> +       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
> +       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>         unsigned long flags;
>         bool ret;
>
> -       if (HAS_PCH_LPT(dev)) {
> -               crtc = NULL;
> -               for_each_pipe(p) {
> -                       struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p];
> -                       if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) {
> -                               crtc = c;
> -                               break;
> -                       }
> -               }
> -               if (!crtc) {
> -                       DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n");
> -                       return false;
> -               }
> -       } else {
> -               crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
> -       }
> -       intel_crtc = to_intel_crtc(crtc);
> -
>         spin_lock_irqsave(&dev_priv->irq_lock, flags);
>
>         ret = !intel_crtc->pch_fifo_underrun_disabled;
> @@ -326,7 +307,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
>         intel_crtc->pch_fifo_underrun_disabled = !enable;
>
>         if (HAS_PCH_IBX(dev))
> -               ibx_set_fifo_underrun_reporting(intel_crtc, enable);
> +               ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
>         else
>                 cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
>
> --
> 1.8.1.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 04/24] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/
  2013-06-12 11:37 ` [PATCH 04/24] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
@ 2013-06-12 14:22   ` Egbert Eich
  0 siblings, 0 replies; 86+ messages in thread
From: Egbert Eich @ 2013-06-12 14:22 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Egbert Eich, Intel Graphics Development

Daniel Vetter writes:
 > The combination of Paulo's fifo underrun detection code and Egbert's
 > hpd storm handling code unfortunately made the hpd storm handling code
 > racy.
 > 
 > To avoid duplicating tricky interrupt locking code over all platforms
 > start with a bit of refactoring. This patch is the very first step
 > since in the end the irq storm handling code will handle all hotplug
 > logic (and so also encapsulate the locking nicely).
 > 
 > Cc: Egbert Eich <eich@suse.de>
 > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
 > ---
 >  drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++--------
 >  1 file changed, 8 insertions(+), 8 deletions(-)
 > 

[reviewed code deleted]

Reviewed-by: Egbert Eich <eich@suse.de>

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 06/24] drm/i915: fold the queue_work into intel_hpd_irq_handler
  2013-06-12 11:37 ` [PATCH 06/24] drm/i915: fold the queue_work " Daniel Vetter
@ 2013-06-12 14:29   ` Egbert Eich
  0 siblings, 0 replies; 86+ messages in thread
From: Egbert Eich @ 2013-06-12 14:29 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Egbert Eich, Intel Graphics Development

Daniel Vetter writes:
 > Everywhere the same.
 > 
 > Cc: Egbert Eich <eich@suse.de>
 > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
 > ---
 >  drivers/gpu/drm/i915/i915_irq.c | 11 +++--------
 >  1 file changed, 3 insertions(+), 8 deletions(-)

[reviewed code deleted]

Reviewed-by: Egbert Eich <eich@suse.de>

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 07/24] drm/i915: fold the no-irq check into intel_hpd_irq_handler
  2013-06-12 11:37 ` [PATCH 07/24] drm/i915: fold the no-irq check " Daniel Vetter
@ 2013-06-12 14:33   ` Egbert Eich
  2013-06-26 22:35     ` Paulo Zanoni
  0 siblings, 1 reply; 86+ messages in thread
From: Egbert Eich @ 2013-06-12 14:33 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Egbert Eich, Intel Graphics Development

Daniel Vetter writes:
 > The usual pattern for our sub-function irq_handlers is that they check
 > for the no-irq case themselves. This results in more streamlined code
 > in the upper irq handlers.
 > 
 > Cc: Egbert Eich <eich@suse.de>
 > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
 > ---
 >  drivers/gpu/drm/i915/i915_irq.c | 33 +++++++++++++++++----------------
 >  1 file changed, 17 insertions(+), 16 deletions(-)
 > 

[reviewed code deleted]

Reviewed-by: Egbert Eich <eich@suse.de>

^ permalink raw reply	[flat|nested] 86+ messages in thread

* [PATCH] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns
  2013-06-12 13:04   ` Paulo Zanoni
@ 2013-06-12 14:46     ` Daniel Vetter
  2013-06-27 20:45       ` Paulo Zanoni
  0 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 14:46 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

It's racy: There's no guarantee that we won't walk this code (due to a
pch fifo underrun interrupt) while someone is changing the pointers
around.

The only reason we do this is to use the righ crtc for the pch fifo
underrun accounting. But we never expose this to userspace, so
essentially no one really cares if we use the "wrong" crtc.

So let's just rip it out.

With this patch fifo underrun code will always use crtc A for tracking
underruns on the (only) pch transcoder on LPT.

v2: Add a big comment explaining what's going on. Requested by Paulo.

Cc: Paulo Zanoni <przanoni@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++-------------------------
 1 file changed, 15 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index bb26555..e80c610 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -193,13 +193,13 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
 	POSTING_READ(SDEIMR);
 }
 
-static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
+static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
+					    enum transcoder pch_transcoder,
 					    bool enable)
 {
-	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
-						SDE_TRANSB_FIFO_UNDER;
+	uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
+		       SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
 
 	ibx_display_interrupt_update(dev_priv, bit,
 				     enable ? bit : 0);
@@ -292,29 +292,19 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
 					   bool enable)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	enum pipe p;
-	struct drm_crtc *crtc;
-	struct intel_crtc *intel_crtc;
+	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	unsigned long flags;
 	bool ret;
 
-	if (HAS_PCH_LPT(dev)) {
-		crtc = NULL;
-		for_each_pipe(p) {
-			struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p];
-			if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) {
-				crtc = c;
-				break;
-			}
-		}
-		if (!crtc) {
-			DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n");
-			return false;
-		}
-	} else {
-		crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
-	}
-	intel_crtc = to_intel_crtc(crtc);
+	/*
+	 * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
+	 * has has only one pch transcoder A that all pipes can use. To avoid
+	 * racy pch transcoder -> pipe lookups from interrupt code simply store
+	 * the underrun statistics in crtc A. Since we never expose this
+	 * anywhere nor use it outside of the fifo underrun code here using the
+	 * "wrong" crtc on LPT won't cause issues.
+	 */
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
 
@@ -326,7 +316,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
 	intel_crtc->pch_fifo_underrun_disabled = !enable;
 
 	if (HAS_PCH_IBX(dev))
-		ibx_set_fifo_underrun_reporting(intel_crtc, enable);
+		ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
 	else
 		cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* Re: [PATCH 08/24] drm/i915: fix hpd interrupt register locking
  2013-06-12 11:37 ` [PATCH 08/24] " Daniel Vetter
@ 2013-06-12 14:59   ` Egbert Eich
  2013-06-12 15:10     ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Egbert Eich @ 2013-06-12 14:59 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Egbert Eich, Intel Graphics Development

Daniel Vetter writes:
 > Our interrupt handler (in hardird context) could race with the timer
                          Nitpick: s/d/q/

 > (in softirq context), hence we need to hold the spinlock around the
 > call to ->hdp_irq_setup in intel_hpd_irq_handler, too.
 > 
 > But as an optimization (and more so to clarify things) we don't need
 > to do the irqsave/restore dance in the hardirq context.
 > 
 > Note also that on ilk+ the race isn't just against the hotplug
 > reenable timer, but also against the fifo underrun reporting. That one
 > also modifies the SDEIMR register (again protected by the same
 > dev_priv->irq_lock).
 > 
 > To lock things down again sprinkle a assert_spin_locked. But exclude
 > the functions touching SDEIMR for now, I want to extract them all into
 > a new helper function (like we do already for pipestate, display
 > interrupts and all the various gt interrupts).
 > 
 > Cc: Egbert Eich <eich@suse.de>
 > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
 > ---
 >  drivers/gpu/drm/i915/i915_irq.c | 15 ++++++++++-----
 >  1 file changed, 10 insertions(+), 5 deletions(-)
 > 
 > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
 > index 1815891..95e15cd 100644
 > --- a/drivers/gpu/drm/i915/i915_irq.c
 > +++ b/drivers/gpu/drm/i915/i915_irq.c
 > @@ -880,15 +880,13 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 >  					 const u32 *hpd)
 >  {
 >  	drm_i915_private_t *dev_priv = dev->dev_private;
 > -	unsigned long irqflags;
 >  	int i;
 >  	bool storm_detected = false;
 >  
 >  	if (!hotplug_trigger)
 >  		return;
 >  
 > -	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 > -
 > +	spin_lock(&dev_priv->irq_lock);
 >  	for (i = 1; i < HPD_NUM_PINS; i++) {
 >  
 >  		if (!(hpd[i] & hotplug_trigger) ||
 > @@ -911,10 +909,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 >  		}
 >  	}
 >  
 > -	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 > -
 >  	if (storm_detected)
 >  		dev_priv->display.hpd_irq_setup(dev);
 > +	spin_unlock(&dev_priv->irq_lock);
 >  
 >  	queue_work(dev_priv->wq,
 >  		   &dev_priv->hotplug_work);
 > @@ -3327,6 +3324,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
 >  	struct intel_encoder *intel_encoder;
 >  	u32 hotplug_en;
 >  
 > +	assert_spin_locked(&dev_priv->irq_lock);
 > +
 >  	if (I915_HAS_HOTPLUG(dev)) {
 >  		hotplug_en = I915_READ(PORT_HOTPLUG_EN);
 >  		hotplug_en &= ~HOTPLUG_INT_EN_MASK;


Didn't you want to do the same for ibx_hpd_irq_setup() ?

 > @@ -3610,6 +3609,7 @@ void intel_hpd_init(struct drm_device *dev)
 >  	struct drm_i915_private *dev_priv = dev->dev_private;
 >  	struct drm_mode_config *mode_config = &dev->mode_config;
 >  	struct drm_connector *connector;
 > +	unsigned long irqflags;
 >  	int i;
 >  
 >  	for (i = 1; i < HPD_NUM_PINS; i++) {
 > @@ -3622,6 +3622,11 @@ void intel_hpd_init(struct drm_device *dev)
 >  		if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
 >  			connector->polled = DRM_CONNECTOR_POLL_HPD;
 >  	}
 > +
 > +	/* Interrup setup is already guaranteed to be single-threaded, this is

Nitpick -  missed a 't'.

 > +	 * just to make the assert_spin_locked checks happy. */
 > +	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 >  	if (dev_priv->display.hpd_irq_setup)
 >  		dev_priv->display.hpd_irq_setup(dev);
 > +	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 >  }
 > -- 
 > 1.8.1.4

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 05/24] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler
       [not found]   ` <20920.34096.704203.67316@linux-qknr.site>
@ 2013-06-12 15:00     ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 15:00 UTC (permalink / raw)
  To: Egbert Eich; +Cc: intel-gfx

On Wed, Jun 12, 2013 at 4:26 PM, Egbert Eich <eich@suse.com> wrote:
> Daniel Vetter writes:
>  > We already have a vfunc for this (and other parts of the hpd storm
>  > handling code already use it).
>  >
>  > Cc: Egbert Eich <eich@suse.de>
>  > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>  > ---
>  >  drivers/gpu/drm/i915/i915_irq.c | 29 +++++++++++------------------
>  >  1 file changed, 11 insertions(+), 18 deletions(-)
>  >
>
> [ reviewed code deleted ]
>
> Reviewed-by: Egbert Eich <eich@suse.de>

Readd intel-gfx so I don't miss the r-b tag.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 08/24] drm/i915: fix hpd interrupt register locking
  2013-06-12 14:59   ` Egbert Eich
@ 2013-06-12 15:10     ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 15:10 UTC (permalink / raw)
  To: Egbert Eich; +Cc: Egbert Eich, Intel Graphics Development

On Wed, Jun 12, 2013 at 4:59 PM, Egbert Eich <eich@suse.com> wrote:
>  > +    assert_spin_locked(&dev_priv->irq_lock);
>  > +
>  >      if (I915_HAS_HOTPLUG(dev)) {
>  >              hotplug_en = I915_READ(PORT_HOTPLUG_EN);
>  >              hotplug_en &= ~HOTPLUG_INT_EN_MASK;
>
>
> Didn't you want to do the same for ibx_hpd_irq_setup() ?

Will happen in a follow-up patch, since I first consolidate all access
to SDEIMR into one single helper function. I've tried to explain that
a bit in the commit message but failed to make the connection to
ibx_hpd_irq_setup - once we have the helper function the
assert_spin_locked is in there and so ibx_hpd_irq_setup doesn't need
its own check (since it won't touch SDEIMR directly any more).
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT
  2013-06-12 11:37 ` [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT Daniel Vetter
@ 2013-06-12 17:13   ` Ben Widawsky
  2013-06-12 17:18     ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Ben Widawsky @ 2013-06-12 17:13 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 01:37:21PM +0200, Daniel Vetter wrote:
> The code to handle it is broken - there's simply no code to clear CS
> parser errors on gen5+. And behold, for all the other rings we also
> don't enable it!
> 
> Leave the handling code itself in place just to be consistent with the
> existing mess though. And in case someone feels like fixing it all up.
> 
> This has been errornously enabled in
> 
> commit 12638c57f31952127c734c26315e1348fa1334c2
> Author: Ben Widawsky <ben@bwidawsk.net>
> Date:   Tue May 28 19:22:31 2013 -0700
> 
>     drm/i915: Enable vebox interrupts
> 
> Cc: Damien Lespiau <damien.lespiau@intel.com>
> Cc: Ben Widawsky <ben@bwidawsk.net>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
Why not fix the problem instead of just disabling the interrupt? Then
the "existing mess" is justified. It really shouldn't be terribly
difficult to fix it.

[snip]
-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT
  2013-06-12 17:13   ` Ben Widawsky
@ 2013-06-12 17:18     ` Daniel Vetter
  2013-06-12 18:19       ` Ben Widawsky
  0 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 17:18 UTC (permalink / raw)
  To: Ben Widawsky; +Cc: Daniel Vetter, Intel Graphics Development

On Wed, Jun 12, 2013 at 10:13:41AM -0700, Ben Widawsky wrote:
> On Wed, Jun 12, 2013 at 01:37:21PM +0200, Daniel Vetter wrote:
> > The code to handle it is broken - there's simply no code to clear CS
> > parser errors on gen5+. And behold, for all the other rings we also
> > don't enable it!
> > 
> > Leave the handling code itself in place just to be consistent with the
> > existing mess though. And in case someone feels like fixing it all up.
> > 
> > This has been errornously enabled in
> > 
> > commit 12638c57f31952127c734c26315e1348fa1334c2
> > Author: Ben Widawsky <ben@bwidawsk.net>
> > Date:   Tue May 28 19:22:31 2013 -0700
> > 
> >     drm/i915: Enable vebox interrupts
> > 
> > Cc: Damien Lespiau <damien.lespiau@intel.com>
> > Cc: Ben Widawsky <ben@bwidawsk.net>
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >
> Why not fix the problem instead of just disabling the interrupt? Then
> the "existing mess" is justified. It really shouldn't be terribly
> difficult to fix it.

Haven't seen it proven useful, and I don't want to blow through time just
for fun on it. Hangcheck seems to be able to deal with it just fine.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT
  2013-06-12 17:18     ` Daniel Vetter
@ 2013-06-12 18:19       ` Ben Widawsky
  2013-06-12 18:32         ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Ben Widawsky @ 2013-06-12 18:19 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development

On Wed, Jun 12, 2013 at 07:18:38PM +0200, Daniel Vetter wrote:
> On Wed, Jun 12, 2013 at 10:13:41AM -0700, Ben Widawsky wrote:
> > On Wed, Jun 12, 2013 at 01:37:21PM +0200, Daniel Vetter wrote:
> > > The code to handle it is broken - there's simply no code to clear CS
> > > parser errors on gen5+. And behold, for all the other rings we also
> > > don't enable it!
> > > 
> > > Leave the handling code itself in place just to be consistent with the
> > > existing mess though. And in case someone feels like fixing it all up.
> > > 
> > > This has been errornously enabled in
> > > 
> > > commit 12638c57f31952127c734c26315e1348fa1334c2
> > > Author: Ben Widawsky <ben@bwidawsk.net>
> > > Date:   Tue May 28 19:22:31 2013 -0700
> > > 
> > >     drm/i915: Enable vebox interrupts
> > > 
> > > Cc: Damien Lespiau <damien.lespiau@intel.com>
> > > Cc: Ben Widawsky <ben@bwidawsk.net>
> > > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > >
> > Why not fix the problem instead of just disabling the interrupt? Then
> > the "existing mess" is justified. It really shouldn't be terribly
> > difficult to fix it.
> 
> Haven't seen it proven useful, and I don't want to blow through time just
> for fun on it. Hangcheck seems to be able to deal with it just fine.
> -Daniel
I don't get it. Isn't it just clearing a bit in the handler, vs.
clearing the flag here?

> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT
  2013-06-12 18:19       ` Ben Widawsky
@ 2013-06-12 18:32         ` Daniel Vetter
  2013-06-12 18:51           ` Ben Widawsky
  2013-06-28 17:25           ` Ben Widawsky
  0 siblings, 2 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-12 18:32 UTC (permalink / raw)
  To: Ben Widawsky; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 8:19 PM, Ben Widawsky <ben@bwidawsk.net> wrote:
> On Wed, Jun 12, 2013 at 07:18:38PM +0200, Daniel Vetter wrote:
>> On Wed, Jun 12, 2013 at 10:13:41AM -0700, Ben Widawsky wrote:
>> > On Wed, Jun 12, 2013 at 01:37:21PM +0200, Daniel Vetter wrote:
>> > > The code to handle it is broken - there's simply no code to clear CS
>> > > parser errors on gen5+. And behold, for all the other rings we also
>> > > don't enable it!
>> > >
>> > > Leave the handling code itself in place just to be consistent with the
>> > > existing mess though. And in case someone feels like fixing it all up.
>> > >
>> > > This has been errornously enabled in
>> > >
>> > > commit 12638c57f31952127c734c26315e1348fa1334c2
>> > > Author: Ben Widawsky <ben@bwidawsk.net>
>> > > Date:   Tue May 28 19:22:31 2013 -0700
>> > >
>> > >     drm/i915: Enable vebox interrupts
>> > >
>> > > Cc: Damien Lespiau <damien.lespiau@intel.com>
>> > > Cc: Ben Widawsky <ben@bwidawsk.net>
>> > > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>> > >
>> > Why not fix the problem instead of just disabling the interrupt? Then
>> > the "existing mess" is justified. It really shouldn't be terribly
>> > difficult to fix it.
>>
>> Haven't seen it proven useful, and I don't want to blow through time just
>> for fun on it. Hangcheck seems to be able to deal with it just fine.
>> -Daniel
> I don't get it. Isn't it just clearing a bit in the handler, vs.
> clearing the flag here?

On a quick Bspec read we'd need to set up per-ring error interrupt
registers, put them to sensible value in them, wire up the interrupt
handling for each ring since ilk+ and then also test it. I really
don't see the point in doing that. The only upshot of all that work is
that if there's an instruction error we'd get an interrupt instead of
waiting for the hangcheck to kick in.

If you insist I can follow-up with a patch to just rip out the
bare-bones handler we have now. Everything else really feels like
wasted effort to me.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT
  2013-06-12 18:32         ` Daniel Vetter
@ 2013-06-12 18:51           ` Ben Widawsky
  2013-06-28 17:25           ` Ben Widawsky
  1 sibling, 0 replies; 86+ messages in thread
From: Ben Widawsky @ 2013-06-12 18:51 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 08:32:44PM +0200, Daniel Vetter wrote:
> On Wed, Jun 12, 2013 at 8:19 PM, Ben Widawsky <ben@bwidawsk.net> wrote:
> > On Wed, Jun 12, 2013 at 07:18:38PM +0200, Daniel Vetter wrote:
> >> On Wed, Jun 12, 2013 at 10:13:41AM -0700, Ben Widawsky wrote:
> >> > On Wed, Jun 12, 2013 at 01:37:21PM +0200, Daniel Vetter wrote:
> >> > > The code to handle it is broken - there's simply no code to clear CS
> >> > > parser errors on gen5+. And behold, for all the other rings we also
> >> > > don't enable it!
> >> > >
> >> > > Leave the handling code itself in place just to be consistent with the
> >> > > existing mess though. And in case someone feels like fixing it all up.
> >> > >
> >> > > This has been errornously enabled in
> >> > >
> >> > > commit 12638c57f31952127c734c26315e1348fa1334c2
> >> > > Author: Ben Widawsky <ben@bwidawsk.net>
> >> > > Date:   Tue May 28 19:22:31 2013 -0700
> >> > >
> >> > >     drm/i915: Enable vebox interrupts
> >> > >
> >> > > Cc: Damien Lespiau <damien.lespiau@intel.com>
> >> > > Cc: Ben Widawsky <ben@bwidawsk.net>
> >> > > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >> > >
> >> > Why not fix the problem instead of just disabling the interrupt? Then
> >> > the "existing mess" is justified. It really shouldn't be terribly
> >> > difficult to fix it.
> >>
> >> Haven't seen it proven useful, and I don't want to blow through time just
> >> for fun on it. Hangcheck seems to be able to deal with it just fine.
> >> -Daniel
> > I don't get it. Isn't it just clearing a bit in the handler, vs.
> > clearing the flag here?
> 
> On a quick Bspec read we'd need to set up per-ring error interrupt
> registers, put them to sensible value in them, wire up the interrupt
> handling for each ring since ilk+ and then also test it. I really
> don't see the point in doing that. The only upshot of all that work is
> that if there's an instruction error we'd get an interrupt instead of
> waiting for the hangcheck to kick in.
> 
> If you insist I can follow-up with a patch to just rip out the
> bare-bones handler we have now. Everything else really feels like
> wasted effort to me.
> -Daniel

No. I don't insist. I was just thinking these kind of error interrupts
should be always on, like L3 parity. But that is indeed more than just
clearing a bit (though not THAT much).

-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 24/24] drm/i915: simplify rps interrupt enabling/disabling sequence
  2013-06-12 11:37 ` [PATCH 24/24] drm/i915: simplify rps interrupt enabling/disabling sequence Daniel Vetter
@ 2013-06-12 22:32   ` Ben Widawsky
  0 siblings, 0 replies; 86+ messages in thread
From: Ben Widawsky @ 2013-06-12 22:32 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 01:37:26PM +0200, Daniel Vetter wrote:
> At the moment we have the following interrupt enabling sequence:
> 1. irq preinstall hook
> 2. enabling the interrupt handler and calling irq postinstall hook
> 3. enable rps interrupts from the async work
> 
> And the folliwing disable sequence:
> 1. disabling the interrupt handler and calling the uninstall hook
> 2. disabling the rps interrupt
> 
> Since the postinstall hook now always sets up PMIIR, PMIER and PMIMR
> to known-good states there no way for an interrupt to sneak in in the
> enable sequence, so we can reinstate the WARN lost in
> 
> commit eda63ffb906c2fb3b609a0e87aeb63c0f25b9e6b
> Author: Ben Widawsky <ben@bwidawsk.net>
> Date:   Tue May 28 19:22:26 2013 -0700
> 
>     drm/i915: Add PM regs to pre/post install
> 
> Note that there's some room for future cleanups since most of the
> interrupt register clearing in the disable function is rather
> redundant. But that's better done in follow-up patches, if at all.
> 
> Cc: Ben Widawsky <ben@bwidawsk.net>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>

Reviewed-by: Ben Widawsky <ben@bwidawsk.net>

Assuming the first 23 patches fixed it all :-)

-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* [PATCH] drm/i915: fix locking around ironlake_enable|disable_display_irq
  2013-06-12 11:37 ` [PATCH 01/24] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
@ 2013-06-25 12:26   ` Daniel Vetter
  2013-06-26 21:15     ` Paulo Zanoni
  0 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-25 12:26 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

The haswell unclaimed register handling code forgot to take the
spinlock. Since this is in the context of the non-rentrant interupt
handler and we only have one interrupt handler it is sufficient to
just grab the spinlock - we do not need to exclude any other
interrupts from running on the same cpu.

To prevent such gaffles in the future sprinkle assert_spin_locked over
these functions. Unfornately this requires us to hold the spinlock in
the ironlake postinstall hook where it is not strictly required:
Currently that is run in single-threaded context and with userspace
exlcuded from running concurrent ioctls. Add a comment explaining
this.

v2: ivb_can_enable_err_int also needs to be protected by the spinlock.
To ensure this won't happen in the future again also sprinkle a
spinlock assert in there.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index c482e8a..ff1fed4 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -95,6 +95,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev);
 static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((dev_priv->irq_mask & mask) != 0) {
 		dev_priv->irq_mask &= ~mask;
 		I915_WRITE(DEIMR, dev_priv->irq_mask);
@@ -105,6 +107,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 static void
 ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((dev_priv->irq_mask & mask) != mask) {
 		dev_priv->irq_mask |= mask;
 		I915_WRITE(DEIMR, dev_priv->irq_mask);
@@ -118,6 +122,8 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
 	struct intel_crtc *crtc;
 	enum pipe pipe;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	for_each_pipe(pipe) {
 		crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 
@@ -1218,8 +1224,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 	/* On Haswell, also mask ERR_INT because we don't want to risk
 	 * generating "unclaimed register" interrupts from inside the interrupt
 	 * handler. */
-	if (IS_HASWELL(dev))
+	if (IS_HASWELL(dev)) {
+		spin_lock(&dev_priv->irq_lock);
 		ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+		spin_unlock(&dev_priv->irq_lock);
+	}
 
 	gt_iir = I915_READ(GTIIR);
 	if (gt_iir) {
@@ -1272,8 +1281,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 		ret = IRQ_HANDLED;
 	}
 
-	if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev))
-		ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+	if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev)) {
+		spin_lock(&dev_priv->irq_lock);
+		if (ivb_can_enable_err_int(dev))
+			ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+		spin_unlock(&dev_priv->irq_lock);
+	}
 
 	I915_WRITE(DEIER, de_ier);
 	POSTING_READ(DEIER);
@@ -2633,6 +2646,8 @@ static void ibx_irq_postinstall(struct drm_device *dev)
 
 static int ironlake_irq_postinstall(struct drm_device *dev)
 {
+	unsigned long irqflags;
+
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	/* enable kind of interrupts always enabled */
 	u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
@@ -2671,7 +2686,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 		/* Clear & enable PCU event interrupts */
 		I915_WRITE(DEIIR, DE_PCU_EVENT);
 		I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
+
+		/* spinlocking not required here for correctness since interrupt
+		 * setup is guaranteed to run in single-threaded context. But we
+		 * need it to make the assert_spin_locked happy. */
+		spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 		ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
+		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 	}
 
 	return 0;
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH] drm/i915: extract ibx_display_interrupt_update
  2013-06-12 11:37 ` [PATCH 09/24] drm/i915: extract ibx_display_interrupt_update Daniel Vetter
@ 2013-06-25 12:27   ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-25 12:27 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

This way all changes to SDEIMR all go through the same function, with
the exception of the (single-threaded) setup/teardown code.

For paranoia again add an assert_spin_locked.

v2: For even more paranoia also sprinkle a spinlock assert over
cpt_can_enable_serr_int since we need to have that one there, too.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 44 ++++++++++++++++++++++++-----------------
 1 file changed, 26 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 033132b..363caab 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -137,6 +137,8 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
 	enum pipe pipe;
 	struct intel_crtc *crtc;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	for_each_pipe(pipe) {
 		crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 
@@ -179,6 +181,20 @@ static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
 	}
 }
 
+static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
+					 uint32_t interrupt_mask,
+					 uint32_t enabled_irq_mask)
+{
+	uint32_t sdeimr = I915_READ(SDEIMR);
+	sdeimr &= ~interrupt_mask;
+	sdeimr |= ~enabled_irq_mask;
+
+	assert_spin_locked(&dev_priv->irq_lock);
+
+	I915_WRITE(SDEIMR, sdeimr);
+	POSTING_READ(SDEIMR);
+}
+
 static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
 					    bool enable)
 {
@@ -187,12 +203,8 @@ static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
 	uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
 						SDE_TRANSB_FIFO_UNDER;
 
-	if (enable)
-		I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~bit);
-	else
-		I915_WRITE(SDEIMR, I915_READ(SDEIMR) | bit);
-
-	POSTING_READ(SDEIMR);
+	ibx_display_interrupt_update(dev_priv, bit,
+				     enable ? bit : 0);
 }
 
 static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
@@ -208,13 +220,10 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
 		I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN |
 				     SERR_INT_TRANS_B_FIFO_UNDERRUN |
 				     SERR_INT_TRANS_C_FIFO_UNDERRUN);
-
-		I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~SDE_ERROR_CPT);
-	} else {
-		I915_WRITE(SDEIMR, I915_READ(SDEIMR) | SDE_ERROR_CPT);
 	}
 
-	POSTING_READ(SDEIMR);
+	ibx_display_interrupt_update(dev_priv, SDE_ERROR_CPT,
+				     enable ? SDE_ERROR_CPT : 0);
 }
 
 /**
@@ -2588,22 +2597,21 @@ static void ibx_hpd_irq_setup(struct drm_device *dev)
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct intel_encoder *intel_encoder;
-	u32 mask = ~I915_READ(SDEIMR);
-	u32 hotplug;
+	u32 hotplug_irqs, hotplug, enabled_irqs = 0;
 
 	if (HAS_PCH_IBX(dev)) {
-		mask &= ~SDE_HOTPLUG_MASK;
+		hotplug_irqs = SDE_HOTPLUG_MASK;
 		list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
 			if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
-				mask |= hpd_ibx[intel_encoder->hpd_pin];
+				enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin];
 	} else {
-		mask &= ~SDE_HOTPLUG_MASK_CPT;
+		hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
 		list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
 			if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
-				mask |= hpd_cpt[intel_encoder->hpd_pin];
+				enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin];
 	}
 
-	I915_WRITE(SDEIMR, ~mask);
+	ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
 
 	/*
 	 * Enable digital hotplug on the PCH, and configure the DP short pulse
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH] drm/i915: irq handlers don't need interrupt-safe spinlocks
  2013-06-12 11:37 ` [PATCH 14/24] drm/i915: irq handlers don't need interrupt-safe spinlocks Daniel Vetter
@ 2013-06-25 12:27   ` Daniel Vetter
  2013-06-27 21:14     ` Paulo Zanoni
  0 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-25 12:27 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Since we only have one interrupt handler and interrupt handlers are
non-reentrant.

To drive the point really home give them all an _irq_handler suffix.

This is a tiny micro-optimization but even more important it makes it
clearer what locking we actually need. And in case someone screws this
up: lockdep will catch hardirq vs. other context deadlocks.

v2: Fix up compile fail.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 42 ++++++++++++++++++-----------------------
 1 file changed, 18 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 3e6524a..6906b0f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -646,14 +646,13 @@ static void i915_hotplug_work_func(struct work_struct *work)
 		drm_kms_helper_hotplug_event(dev);
 }
 
-static void ironlake_handle_rps_change(struct drm_device *dev)
+static void ironlake_rps_change_irq_handler(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 busy_up, busy_down, max_avg, min_avg;
 	u8 new_delay;
-	unsigned long flags;
 
-	spin_lock_irqsave(&mchdev_lock, flags);
+	spin_lock(&mchdev_lock);
 
 	I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
 
@@ -681,7 +680,7 @@ static void ironlake_handle_rps_change(struct drm_device *dev)
 	if (ironlake_set_drps(dev, new_delay))
 		dev_priv->ips.cur_delay = new_delay;
 
-	spin_unlock_irqrestore(&mchdev_lock, flags);
+	spin_unlock(&mchdev_lock);
 
 	return;
 }
@@ -817,18 +816,17 @@ static void ivybridge_parity_work(struct work_struct *work)
 	kfree(parity_event[1]);
 }
 
-static void ivybridge_handle_parity_error(struct drm_device *dev)
+static void ivybridge_parity_error_irq_handler(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	unsigned long flags;
 
 	if (!HAS_L3_GPU_CACHE(dev))
 		return;
 
-	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	spin_lock(&dev_priv->irq_lock);
 	dev_priv->gt_irq_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+	spin_unlock(&dev_priv->irq_lock);
 
 	queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
 }
@@ -854,15 +852,13 @@ static void snb_gt_irq_handler(struct drm_device *dev,
 	}
 
 	if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
-		ivybridge_handle_parity_error(dev);
+		ivybridge_parity_error_irq_handler(dev);
 }
 
 /* Legacy way of handling PM interrupts */
-static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
-				u32 pm_iir)
+static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv,
+				 u32 pm_iir)
 {
-	unsigned long flags;
-
 	/*
 	 * IIR bits should never already be set because IMR should
 	 * prevent an interrupt from being shown in IIR. The warning
@@ -873,11 +869,11 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
 	 * The mask bit in IMR is cleared by dev_priv->rps.work.
 	 */
 
-	spin_lock_irqsave(&dev_priv->rps.lock, flags);
+	spin_lock(&dev_priv->rps.lock);
 	dev_priv->rps.pm_iir |= pm_iir;
 	I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
 	POSTING_READ(GEN6_PMIMR);
-	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+	spin_unlock(&dev_priv->rps.lock);
 
 	queue_work(dev_priv->wq, &dev_priv->rps.work);
 }
@@ -941,7 +937,7 @@ static void dp_aux_irq_handler(struct drm_device *dev)
 	wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
-/* Unlike gen6_queue_rps_work() from which this function is originally derived,
+/* Unlike gen6_rps_irq_handler() from which this function is originally derived,
  * we must be able to deal with other PM interrupts. This is complicated because
  * of the way in which we use the masks to defer the RPS work (which for
  * posterity is necessary because of forcewake).
@@ -949,9 +945,7 @@ static void dp_aux_irq_handler(struct drm_device *dev)
 static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
 			       u32 pm_iir)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_priv->rps.lock, flags);
+	spin_lock(&dev_priv->rps.lock);
 	dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
 	if (dev_priv->rps.pm_iir) {
 		I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
@@ -960,7 +954,7 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
 		/* TODO: if queue_work is slow, move it out of the spinlock */
 		queue_work(dev_priv->wq, &dev_priv->rps.work);
 	}
-	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+	spin_unlock(&dev_priv->rps.lock);
 
 	if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
 		if (pm_iir & PM_VEBOX_USER_INTERRUPT)
@@ -1042,7 +1036,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 			gmbus_irq_handler(dev);
 
 		if (pm_iir & GEN6_PM_RPS_EVENTS)
-			gen6_queue_rps_work(dev_priv, pm_iir);
+			gen6_rps_irq_handler(dev_priv, pm_iir);
 
 		I915_WRITE(GTIIR, gt_iir);
 		I915_WRITE(GEN6_PMIIR, pm_iir);
@@ -1280,7 +1274,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 		if (IS_HASWELL(dev))
 			hsw_pm_irq_handler(dev_priv, pm_iir);
 		else if (pm_iir & GEN6_PM_RPS_EVENTS)
-			gen6_queue_rps_work(dev_priv, pm_iir);
+			gen6_rps_irq_handler(dev_priv, pm_iir);
 		I915_WRITE(GEN6_PMIIR, pm_iir);
 		ret = IRQ_HANDLED;
 	}
@@ -1397,10 +1391,10 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 	}
 
 	if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT)
-		ironlake_handle_rps_change(dev);
+		ironlake_rps_change_irq_handler(dev);
 
 	if (IS_GEN6(dev) && pm_iir & GEN6_PM_RPS_EVENTS)
-		gen6_queue_rps_work(dev_priv, pm_iir);
+		gen6_rps_irq_handler(dev_priv, pm_iir);
 
 	I915_WRITE(GTIIR, gt_iir);
 	I915_WRITE(DEIIR, de_iir);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH] drm/i915: streamline hsw_pm_irq_handler
  2013-06-12 11:37 ` [PATCH 15/24] drm/i915: streamline hsw_pm_irq_handler Daniel Vetter
@ 2013-06-25 12:28   ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-25 12:28 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

The if (pm_iir & ~GEN6_PM_RPS_EVENTS) check was redunandant. Otoh
adding a check for rps events allows us to avoid the spinlock grabbing
for VECS interrupts.

v2: Drop misplaced hunk which now moved to the right patch.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 6906b0f..8ba3f4b 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -945,25 +945,23 @@ static void dp_aux_irq_handler(struct drm_device *dev)
 static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
 			       u32 pm_iir)
 {
-	spin_lock(&dev_priv->rps.lock);
-	dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
-	if (dev_priv->rps.pm_iir) {
+	if (pm_iir & GEN6_PM_RPS_EVENTS) {
+		spin_lock(&dev_priv->rps.lock);
+		dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
 		I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
 		/* never want to mask useful interrupts. (also posting read) */
 		WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
 		/* TODO: if queue_work is slow, move it out of the spinlock */
 		queue_work(dev_priv->wq, &dev_priv->rps.work);
+		spin_unlock(&dev_priv->rps.lock);
 	}
-	spin_unlock(&dev_priv->rps.lock);
 
-	if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
-		if (pm_iir & PM_VEBOX_USER_INTERRUPT)
-			notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
+	if (pm_iir & PM_VEBOX_USER_INTERRUPT)
+		notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
 
-		if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
-			DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
-			i915_handle_error(dev_priv->dev, false);
-		}
+	if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
+		DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
+		i915_handle_error(dev_priv->dev, false);
 	}
 }
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* Re: [PATCH] drm/i915: fix locking around ironlake_enable|disable_display_irq
  2013-06-25 12:26   ` [PATCH] " Daniel Vetter
@ 2013-06-26 21:15     ` Paulo Zanoni
  2013-06-27 10:37       ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-26 21:15 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

2013/6/25 Daniel Vetter <daniel.vetter@ffwll.ch>:
> The haswell unclaimed register handling code forgot to take the
> spinlock. Since this is in the context of the non-rentrant interupt
> handler and we only have one interrupt handler it is sufficient to
> just grab the spinlock - we do not need to exclude any other
> interrupts from running on the same cpu.
>
> To prevent such gaffles in the future sprinkle assert_spin_locked over
> these functions. Unfornately this requires us to hold the spinlock in
> the ironlake postinstall hook where it is not strictly required:
> Currently that is run in single-threaded context and with userspace
> exlcuded from running concurrent ioctls. Add a comment explaining
> this.
>
> v2: ivb_can_enable_err_int also needs to be protected by the spinlock.
> To ensure this won't happen in the future again also sprinkle a
> spinlock assert in there.

Why does ivb_can_enable_err_int need it? Maybe we should add a comment
inside the function explaining why it needs it.


>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 27 ++++++++++++++++++++++++---
>  1 file changed, 24 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index c482e8a..ff1fed4 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -95,6 +95,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev);
>  static void
>  ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
>  {
> +       assert_spin_locked(&dev_priv->irq_lock);
> +
>         if ((dev_priv->irq_mask & mask) != 0) {
>                 dev_priv->irq_mask &= ~mask;
>                 I915_WRITE(DEIMR, dev_priv->irq_mask);
> @@ -105,6 +107,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
>  static void
>  ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
>  {
> +       assert_spin_locked(&dev_priv->irq_lock);
> +
>         if ((dev_priv->irq_mask & mask) != mask) {
>                 dev_priv->irq_mask |= mask;
>                 I915_WRITE(DEIMR, dev_priv->irq_mask);
> @@ -118,6 +122,8 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
>         struct intel_crtc *crtc;
>         enum pipe pipe;
>
> +       assert_spin_locked(&dev_priv->irq_lock);
> +
>         for_each_pipe(pipe) {
>                 crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
>
> @@ -1218,8 +1224,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>         /* On Haswell, also mask ERR_INT because we don't want to risk
>          * generating "unclaimed register" interrupts from inside the interrupt
>          * handler. */
> -       if (IS_HASWELL(dev))
> +       if (IS_HASWELL(dev)) {
> +               spin_lock(&dev_priv->irq_lock);
>                 ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
> +               spin_unlock(&dev_priv->irq_lock);
> +       }
>
>         gt_iir = I915_READ(GTIIR);
>         if (gt_iir) {
> @@ -1272,8 +1281,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>                 ret = IRQ_HANDLED;
>         }
>
> -       if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev))
> -               ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
> +       if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev)) {
> +               spin_lock(&dev_priv->irq_lock);
> +               if (ivb_can_enable_err_int(dev))

You're calling ivb_can_enable_err_int twice here.


> +                       ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
> +               spin_unlock(&dev_priv->irq_lock);
> +       }
>
>         I915_WRITE(DEIER, de_ier);
>         POSTING_READ(DEIER);
> @@ -2633,6 +2646,8 @@ static void ibx_irq_postinstall(struct drm_device *dev)
>
>  static int ironlake_irq_postinstall(struct drm_device *dev)
>  {
> +       unsigned long irqflags;
> +
>         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
>         /* enable kind of interrupts always enabled */
>         u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
> @@ -2671,7 +2686,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
>                 /* Clear & enable PCU event interrupts */
>                 I915_WRITE(DEIIR, DE_PCU_EVENT);
>                 I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
> +
> +               /* spinlocking not required here for correctness since interrupt
> +                * setup is guaranteed to run in single-threaded context. But we
> +                * need it to make the assert_spin_locked happy. */
> +               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);

If spinlocking is not even required, why take the irqsave one instead
of just spin_lock()?


>                 ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
> +               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
>         }
>
>         return 0;
> --
> 1.8.1.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 02/24] drm/i915: close tiny race in the ilk pcu even interrupt setup
  2013-06-12 11:37 ` [PATCH 02/24] drm/i915: close tiny race in the ilk pcu even interrupt setup Daniel Vetter
@ 2013-06-26 21:20   ` Paulo Zanoni
  0 siblings, 0 replies; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-26 21:20 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

2013/6/12 Daniel Vetter <daniel.vetter@ffwll.ch>:
> By the time we write DEIER in the postinstall hook the interrupt
> handler could run any time. And it does modify DEIER to handle
> interrupts.
>
> Hence the DEIER read-modify-write cycle for enabling the PCU event
> source is racy. Close this races the same way we handle vblank
> interrupts: Unconditionally enable the interrupt in the IER register,
> but conditionally mask it in IMR. The later poses no such race since
> the interrupt handler does not touch DEIMR.
>
> Also update the comment, the clearing has already happened
> unconditionally above.

I don't see an "updated comment". I guess you wanted to s/Clear &
enable/Enable/ ? Anyway:
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 567945f..969da20 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2658,7 +2658,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
>         /* should always can generate irq */
>         I915_WRITE(DEIIR, I915_READ(DEIIR));
>         I915_WRITE(DEIMR, dev_priv->irq_mask);
> -       I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK);
> +       I915_WRITE(DEIER, display_mask |
> +                         DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT);
>         POSTING_READ(DEIER);
>
>         dev_priv->gt_irq_mask = ~0;
> @@ -2680,11 +2681,9 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
>         ibx_irq_postinstall(dev);
>
>         if (IS_IRONLAKE_M(dev)) {
> -               /* Clear & enable PCU event interrupts */
> -               I915_WRITE(DEIIR, DE_PCU_EVENT);
> -               I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
> -
> -               /* spinlocking not required here for correctness since interrupt
> +               /* Clear & enable PCU event interrupts
> +                *
> +                * spinlocking not required here for correctness since interrupt
>                  * setup is guaranteed to run in single-threaded context. But we
>                  * need it to make the assert_spin_locked happy. */
>                 spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> --
> 1.8.1.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 03/24] drm/i915: assert_spin_locked for pipestat interrupt enable/disable
  2013-06-12 11:37 ` [PATCH 03/24] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
@ 2013-06-26 21:44   ` Paulo Zanoni
  0 siblings, 0 replies; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-26 21:44 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

2013/6/12 Daniel Vetter <daniel.vetter@ffwll.ch>:
> Just to keep the paranoia equal also sprinkle locking asserts over the
> pipestat interrupt enable/disable functions.
>
> Again this results in false positives in the interrupt setup. Add
> bogo-locking for these and a big comment explaining why it's there and
> that it's indeed unnecessary.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 16 +++++++++++++++-
>  1 file changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 969da20..c0b6c85 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -329,6 +329,8 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
>         u32 reg = PIPESTAT(pipe);
>         u32 pipestat = I915_READ(reg) & 0x7fff0000;
>
> +       assert_spin_locked(&dev_priv->irq_lock);
> +
>         if ((pipestat & mask) == mask)
>                 return;
>
> @@ -344,6 +346,8 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
>         u32 reg = PIPESTAT(pipe);
>         u32 pipestat = I915_READ(reg) & 0x7fff0000;
>
> +       assert_spin_locked(&dev_priv->irq_lock);
> +
>         if ((pipestat & mask) == 0)
>                 return;
>
> @@ -2681,7 +2685,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
>         ibx_irq_postinstall(dev);
>
>         if (IS_IRONLAKE_M(dev)) {
> -               /* Clear & enable PCU event interrupts
> +               /* Enable PCU event interrupts

Oh, here's the "updated comment" I was looking for in the previous
patch! Looks like it missed the train.


>                  *
>                  * spinlocking not required here for correctness since interrupt
>                  * setup is guaranteed to run in single-threaded context. But we
> @@ -2758,6 +2762,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
>         u32 gt_irqs;
>         u32 enable_mask;
>         u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
> +       unsigned long irqflags;
>
>         enable_mask = I915_DISPLAY_PORT_INTERRUPT;
>         enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
> @@ -2783,9 +2788,13 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
>         I915_WRITE(PIPESTAT(1), 0xffff);
>         POSTING_READ(VLV_IER);
>
> +       /* Interrup setup is already guaranteed to be single-threaded, this is
> +        * just to make the assert_spin_locked check happy. */
> +       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);

I guess the same question about irqsave from patch 1 applies here and below.


>         i915_enable_pipestat(dev_priv, 0, pipestat_enable);
>         i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
>         i915_enable_pipestat(dev_priv, 1, pipestat_enable);
> +       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
>
>         I915_WRITE(VLV_IIR, 0xffffffff);
>         I915_WRITE(VLV_IIR, 0xffffffff);
> @@ -3267,6 +3276,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
>         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
>         u32 enable_mask;
>         u32 error_mask;
> +       unsigned long irqflags;
>
>         /* Unmask the interrupts that we always want on. */
>         dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
> @@ -3285,7 +3295,11 @@ static int i965_irq_postinstall(struct drm_device *dev)
>         if (IS_G4X(dev))
>                 enable_mask |= I915_BSD_USER_INTERRUPT;
>
> +       /* Interrup setup is already guaranteed to be single-threaded, this is
> +        * just to make the assert_spin_locked check happy. */
> +       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>         i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
> +       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
>
>         /*
>          * Enable some error detection, note the instruction error mask
> --
> 1.8.1.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 07/24] drm/i915: fold the no-irq check into intel_hpd_irq_handler
  2013-06-12 14:33   ` Egbert Eich
@ 2013-06-26 22:35     ` Paulo Zanoni
  2013-06-27 10:39       ` Daniel Vetter
  2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
  0 siblings, 2 replies; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-26 22:35 UTC (permalink / raw)
  To: Egbert Eich; +Cc: Egbert Eich, Daniel Vetter, Intel Graphics Development

2013/6/12 Egbert Eich <eich@suse.com>:
> Daniel Vetter writes:
>  > The usual pattern for our sub-function irq_handlers is that they check
>  > for the no-irq case themselves. This results in more streamlined code
>  > in the upper irq handlers.
>  >
>  > Cc: Egbert Eich <eich@suse.de>
>  > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>  > ---
>  >  drivers/gpu/drm/i915/i915_irq.c | 33 +++++++++++++++++----------------
>  >  1 file changed, 17 insertions(+), 16 deletions(-)
>  >
>
> [reviewed code deleted]
>
> Reviewed-by: Egbert Eich <eich@suse.de>

Patches 4, 5, 6 and 7 (all reviewed by Egbert) are also Reviewed-by:
Paulo Zanoni <paulo.r.zanoni@intel.com>

But I do have to notice they don't apply anymore due to
s/hpd_status_i965/hpd_status_i915/

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



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH] drm/i915: fix locking around ironlake_enable|disable_display_irq
  2013-06-26 21:15     ` Paulo Zanoni
@ 2013-06-27 10:37       ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 10:37 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Daniel Vetter, Intel Graphics Development

On Wed, Jun 26, 2013 at 06:15:42PM -0300, Paulo Zanoni wrote:
> 2013/6/25 Daniel Vetter <daniel.vetter@ffwll.ch>:
> > The haswell unclaimed register handling code forgot to take the
> > spinlock. Since this is in the context of the non-rentrant interupt
> > handler and we only have one interrupt handler it is sufficient to
> > just grab the spinlock - we do not need to exclude any other
> > interrupts from running on the same cpu.
> >
> > To prevent such gaffles in the future sprinkle assert_spin_locked over
> > these functions. Unfornately this requires us to hold the spinlock in
> > the ironlake postinstall hook where it is not strictly required:
> > Currently that is run in single-threaded context and with userspace
> > exlcuded from running concurrent ioctls. Add a comment explaining
> > this.
> >
> > v2: ivb_can_enable_err_int also needs to be protected by the spinlock.
> > To ensure this won't happen in the future again also sprinkle a
> > spinlock assert in there.
> 
> Why does ivb_can_enable_err_int need it? Maybe we should add a comment
> inside the function explaining why it needs it.

It does access ->cpu_fifo_underrun_disabled. Just reading that won't race,
but it's important that the subsequent state change is consistent with the
state we've read (i.e. no one must be able to sneak in). Hence we need to
hold the lock around the entire if (can_enable)  do_enable; sequence.
> 
> 
> >
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/i915_irq.c | 27 ++++++++++++++++++++++++---
> >  1 file changed, 24 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index c482e8a..ff1fed4 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -95,6 +95,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev);
> >  static void
> >  ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
> >  {
> > +       assert_spin_locked(&dev_priv->irq_lock);
> > +
> >         if ((dev_priv->irq_mask & mask) != 0) {
> >                 dev_priv->irq_mask &= ~mask;
> >                 I915_WRITE(DEIMR, dev_priv->irq_mask);
> > @@ -105,6 +107,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
> >  static void
> >  ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
> >  {
> > +       assert_spin_locked(&dev_priv->irq_lock);
> > +
> >         if ((dev_priv->irq_mask & mask) != mask) {
> >                 dev_priv->irq_mask |= mask;
> >                 I915_WRITE(DEIMR, dev_priv->irq_mask);
> > @@ -118,6 +122,8 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
> >         struct intel_crtc *crtc;
> >         enum pipe pipe;
> >
> > +       assert_spin_locked(&dev_priv->irq_lock);
> > +
> >         for_each_pipe(pipe) {
> >                 crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> >
> > @@ -1218,8 +1224,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
> >         /* On Haswell, also mask ERR_INT because we don't want to risk
> >          * generating "unclaimed register" interrupts from inside the interrupt
> >          * handler. */
> > -       if (IS_HASWELL(dev))
> > +       if (IS_HASWELL(dev)) {
> > +               spin_lock(&dev_priv->irq_lock);
> >                 ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
> > +               spin_unlock(&dev_priv->irq_lock);
> > +       }
> >
> >         gt_iir = I915_READ(GTIIR);
> >         if (gt_iir) {
> > @@ -1272,8 +1281,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
> >                 ret = IRQ_HANDLED;
> >         }
> >
> > -       if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev))
> > -               ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
> > +       if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev)) {
> > +               spin_lock(&dev_priv->irq_lock);
> > +               if (ivb_can_enable_err_int(dev))
> 
> You're calling ivb_can_enable_err_int twice here.

Oops, will fix.

> 
> 
> > +                       ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
> > +               spin_unlock(&dev_priv->irq_lock);
> > +       }
> >
> >         I915_WRITE(DEIER, de_ier);
> >         POSTING_READ(DEIER);
> > @@ -2633,6 +2646,8 @@ static void ibx_irq_postinstall(struct drm_device *dev)
> >
> >  static int ironlake_irq_postinstall(struct drm_device *dev)
> >  {
> > +       unsigned long irqflags;
> > +
> >         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> >         /* enable kind of interrupts always enabled */
> >         u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
> > @@ -2671,7 +2686,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
> >                 /* Clear & enable PCU event interrupts */
> >                 I915_WRITE(DEIIR, DE_PCU_EVENT);
> >                 I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
> > +
> > +               /* spinlocking not required here for correctness since interrupt
> > +                * setup is guaranteed to run in single-threaded context. But we
> > +                * need it to make the assert_spin_locked happy. */
> > +               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> 
> If spinlocking is not even required, why take the irqsave one instead
> of just spin_lock()?

lockdep will complain about the inconsistent locking usage, since just
doing a spin_lock while the interrupt handler could also do a spin_lock
call can deadlock. Ofc lockdep doesn't now that at this point our
interrupt handler can't run, but it's imo established procedure to not
care about such details. So imo this doesn't warrant an extended comment.

> 
> 
> >                 ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
> > +               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> >         }
> >
> >         return 0;
> > --
> > 1.8.1.4
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
> 
> -- 
> Paulo Zanoni

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 07/24] drm/i915: fold the no-irq check into intel_hpd_irq_handler
  2013-06-26 22:35     ` Paulo Zanoni
@ 2013-06-27 10:39       ` Daniel Vetter
  2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
  1 sibling, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 10:39 UTC (permalink / raw)
  To: Paulo Zanoni
  Cc: Egbert Eich, Egbert Eich, Intel Graphics Development, Daniel Vetter

On Wed, Jun 26, 2013 at 07:35:18PM -0300, Paulo Zanoni wrote:
> 2013/6/12 Egbert Eich <eich@suse.com>:
> > Daniel Vetter writes:
> >  > The usual pattern for our sub-function irq_handlers is that they check
> >  > for the no-irq case themselves. This results in more streamlined code
> >  > in the upper irq handlers.
> >  >
> >  > Cc: Egbert Eich <eich@suse.de>
> >  > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >  > ---
> >  >  drivers/gpu/drm/i915/i915_irq.c | 33 +++++++++++++++++----------------
> >  >  1 file changed, 17 insertions(+), 16 deletions(-)
> >  >
> >
> > [reviewed code deleted]
> >
> > Reviewed-by: Egbert Eich <eich@suse.de>
> 
> Patches 4, 5, 6 and 7 (all reviewed by Egbert) are also Reviewed-by:
> Paulo Zanoni <paulo.r.zanoni@intel.com>
> 
> But I do have to notice they don't apply anymore due to
> s/hpd_status_i965/hpd_status_i915/

Yeah, I'll fix up the patches and resend the first 7 anew.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq
  2013-06-26 22:35     ` Paulo Zanoni
  2013-06-27 10:39       ` Daniel Vetter
@ 2013-06-27 11:44       ` Daniel Vetter
  2013-06-27 11:44         ` [PATCH 2/8] drm/i915: close tiny race in the ilk pcu even interrupt setup Daniel Vetter
                           ` (6 more replies)
  1 sibling, 7 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 11:44 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

The haswell unclaimed register handling code forgot to take the
spinlock. Since this is in the context of the non-rentrant interupt
handler and we only have one interrupt handler it is sufficient to
just grab the spinlock - we do not need to exclude any other
interrupts from running on the same cpu.

To prevent such gaffles in the future sprinkle assert_spin_locked over
these functions. Unfornately this requires us to hold the spinlock in
the ironlake postinstall hook where it is not strictly required:
Currently that is run in single-threaded context and with userspace
exlcuded from running concurrent ioctls. Add a comment explaining
this.

v2: ivb_can_enable_err_int also needs to be protected by the spinlock.
To ensure this won't happen in the future again also sprinkle a
spinlock assert in there.

v3: Kill the 2nd call to ivb_can_enable_err_int I've accidentally left
behind, spotted by Paulo.

Cc: Paulo Zanoni <przanoni@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 1da87bf..fa78cf8 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -86,6 +86,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev);
 static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((dev_priv->irq_mask & mask) != 0) {
 		dev_priv->irq_mask &= ~mask;
 		I915_WRITE(DEIMR, dev_priv->irq_mask);
@@ -96,6 +98,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 static void
 ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((dev_priv->irq_mask & mask) != mask) {
 		dev_priv->irq_mask |= mask;
 		I915_WRITE(DEIMR, dev_priv->irq_mask);
@@ -109,6 +113,8 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
 	struct intel_crtc *crtc;
 	enum pipe pipe;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	for_each_pipe(pipe) {
 		crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 
@@ -1217,8 +1223,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 	/* On Haswell, also mask ERR_INT because we don't want to risk
 	 * generating "unclaimed register" interrupts from inside the interrupt
 	 * handler. */
-	if (IS_HASWELL(dev))
+	if (IS_HASWELL(dev)) {
+		spin_lock(&dev_priv->irq_lock);
 		ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+		spin_unlock(&dev_priv->irq_lock);
+	}
 
 	gt_iir = I915_READ(GTIIR);
 	if (gt_iir) {
@@ -1271,8 +1280,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 		ret = IRQ_HANDLED;
 	}
 
-	if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev))
-		ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+	if (IS_HASWELL(dev)) {
+		spin_lock(&dev_priv->irq_lock);
+		if (ivb_can_enable_err_int(dev))
+			ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+		spin_unlock(&dev_priv->irq_lock);
+	}
 
 	I915_WRITE(DEIER, de_ier);
 	POSTING_READ(DEIER);
@@ -2698,6 +2711,8 @@ static void ibx_irq_postinstall(struct drm_device *dev)
 
 static int ironlake_irq_postinstall(struct drm_device *dev)
 {
+	unsigned long irqflags;
+
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	/* enable kind of interrupts always enabled */
 	u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
@@ -2736,7 +2751,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 		/* Clear & enable PCU event interrupts */
 		I915_WRITE(DEIIR, DE_PCU_EVENT);
 		I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
+
+		/* spinlocking not required here for correctness since interrupt
+		 * setup is guaranteed to run in single-threaded context. But we
+		 * need it to make the assert_spin_locked happy. */
+		spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 		ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
+		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 	}
 
 	return 0;
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 2/8] drm/i915: close tiny race in the ilk pcu even interrupt setup
  2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
@ 2013-06-27 11:44         ` Daniel Vetter
  2013-06-27 11:45         ` [PATCH 3/8] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
                           ` (5 subsequent siblings)
  6 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 11:44 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

By the time we write DEIER in the postinstall hook the interrupt
handler could run any time. And it does modify DEIER to handle
interrupts.

Hence the DEIER read-modify-write cycle for enabling the PCU event
source is racy. Close this races the same way we handle vblank
interrupts: Unconditionally enable the interrupt in the IER register,
but conditionally mask it in IMR. The later poses no such race since
the interrupt handler does not touch DEIMR.

Also update the comment, the clearing has already happened
unconditionally above.

v2: Actually shove the updated comment into the right train^W commit,
as spotted by Paulo.

Cc: Paulo Zanoni <przanoni@gmail.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index fa78cf8..465588f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2726,7 +2726,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 	/* should always can generate irq */
 	I915_WRITE(DEIIR, I915_READ(DEIIR));
 	I915_WRITE(DEIMR, dev_priv->irq_mask);
-	I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK);
+	I915_WRITE(DEIER, display_mask |
+			  DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT);
 	POSTING_READ(DEIER);
 
 	dev_priv->gt_irq_mask = ~0;
@@ -2748,11 +2749,9 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 	ibx_irq_postinstall(dev);
 
 	if (IS_IRONLAKE_M(dev)) {
-		/* Clear & enable PCU event interrupts */
-		I915_WRITE(DEIIR, DE_PCU_EVENT);
-		I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
-
-		/* spinlocking not required here for correctness since interrupt
+		/* Enable PCU event interrupts
+		 *
+		 * spinlocking not required here for correctness since interrupt
 		 * setup is guaranteed to run in single-threaded context. But we
 		 * need it to make the assert_spin_locked happy. */
 		spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 3/8] drm/i915: assert_spin_locked for pipestat interrupt enable/disable
  2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
  2013-06-27 11:44         ` [PATCH 2/8] drm/i915: close tiny race in the ilk pcu even interrupt setup Daniel Vetter
@ 2013-06-27 11:45         ` Daniel Vetter
  2013-06-27 11:45         ` [PATCH 4/8] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
                           ` (4 subsequent siblings)
  6 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 11:45 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Just to keep the paranoia equal also sprinkle locking asserts over the
pipestat interrupt enable/disable functions.

Again this results in false positives in the interrupt setup. Add
bogo-locking for these and a big comment explaining why it's there and
that it's indeed unnecessary.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 465588f..4fa33ec 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -322,6 +322,8 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 	u32 reg = PIPESTAT(pipe);
 	u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((pipestat & mask) == mask)
 		return;
 
@@ -337,6 +339,8 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 	u32 reg = PIPESTAT(pipe);
 	u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((pipestat & mask) == 0)
 		return;
 
@@ -2826,6 +2830,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 	u32 gt_irqs;
 	u32 enable_mask;
 	u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
+	unsigned long irqflags;
 
 	enable_mask = I915_DISPLAY_PORT_INTERRUPT;
 	enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
@@ -2851,9 +2856,13 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 	I915_WRITE(PIPESTAT(1), 0xffff);
 	POSTING_READ(VLV_IER);
 
+	/* Interrup setup is already guaranteed to be single-threaded, this is
+	 * just to make the assert_spin_locked check happy. */
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, 0, pipestat_enable);
 	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
 	i915_enable_pipestat(dev_priv, 1, pipestat_enable);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
 	I915_WRITE(VLV_IIR, 0xffffffff);
 	I915_WRITE(VLV_IIR, 0xffffffff);
@@ -3335,6 +3344,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	u32 enable_mask;
 	u32 error_mask;
+	unsigned long irqflags;
 
 	/* Unmask the interrupts that we always want on. */
 	dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
@@ -3353,7 +3363,11 @@ static int i965_irq_postinstall(struct drm_device *dev)
 	if (IS_G4X(dev))
 		enable_mask |= I915_BSD_USER_INTERRUPT;
 
+	/* Interrup setup is already guaranteed to be single-threaded, this is
+	 * just to make the assert_spin_locked check happy. */
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
 	/*
 	 * Enable some error detection, note the instruction error mask
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 4/8] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/
  2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
  2013-06-27 11:44         ` [PATCH 2/8] drm/i915: close tiny race in the ilk pcu even interrupt setup Daniel Vetter
  2013-06-27 11:45         ` [PATCH 3/8] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
@ 2013-06-27 11:45         ` Daniel Vetter
  2013-06-27 11:45         ` [PATCH 5/8] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler Daniel Vetter
                           ` (3 subsequent siblings)
  6 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 11:45 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

The combination of Paulo's fifo underrun detection code and Egbert's
hpd storm handling code unfortunately made the hpd storm handling code
racy.

To avoid duplicating tricky interrupt locking code over all platforms
start with a bit of refactoring. This patch is the very first step
since in the end the irq storm handling code will handle all hotplug
logic (and so also encapsulate the locking nicely).

v2: Rebase on top of the i965g/gm sdvo hpd fix.

Cc: Egbert Eich <eich@suse.de>
Reviewed-by: Egbert Eich <eich@suse.de>
Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 4fa33ec..1da868e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -879,9 +879,9 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
 #define HPD_STORM_DETECT_PERIOD 1000
 #define HPD_STORM_THRESHOLD 5
 
-static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
-					    u32 hotplug_trigger,
-					    const u32 *hpd)
+static inline bool intel_hpd_irq_handler(struct drm_device *dev,
+					 u32 hotplug_trigger,
+					 const u32 *hpd)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned long irqflags;
@@ -1022,7 +1022,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 					 hotplug_status);
 			if (hotplug_trigger) {
-				if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
 					i915_hpd_irq_setup(dev);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
@@ -1053,7 +1053,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
 	if (hotplug_trigger) {
-		if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx))
+		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx))
 			ibx_hpd_irq_setup(dev);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
@@ -1158,7 +1158,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
 	if (hotplug_trigger) {
-		if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt))
+		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt))
 			ibx_hpd_irq_setup(dev);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
@@ -3242,7 +3242,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
 					i915_hpd_irq_setup(dev);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
@@ -3488,7 +3488,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (hotplug_irq_storm_detect(dev, hotplug_trigger,
+				if (intel_hpd_irq_handler(dev, hotplug_trigger,
 							    IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915))
 					i915_hpd_irq_setup(dev);
 				queue_work(dev_priv->wq,
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 5/8] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler
  2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
                           ` (2 preceding siblings ...)
  2013-06-27 11:45         ` [PATCH 4/8] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
@ 2013-06-27 11:45         ` Daniel Vetter
  2013-06-27 11:45         ` [PATCH 6/8] drm/i915: fold the queue_work " Daniel Vetter
                           ` (2 subsequent siblings)
  6 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 11:45 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

We already have a vfunc for this (and other parts of the hpd storm
handling code already use it).

v2: Rebase on top of the i965g/gm sdvo hpd fix.

Cc: Egbert Eich <eich@suse.de>
Reviewed-by: Egbert Eich <eich@suse.de>
Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 1da868e..26c3127 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -79,9 +79,6 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
 };
 
-static void ibx_hpd_irq_setup(struct drm_device *dev);
-static void i915_hpd_irq_setup(struct drm_device *dev);
-
 /* For display hotplug interrupt */
 static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
@@ -879,14 +876,14 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
 #define HPD_STORM_DETECT_PERIOD 1000
 #define HPD_STORM_THRESHOLD 5
 
-static inline bool intel_hpd_irq_handler(struct drm_device *dev,
+static inline void intel_hpd_irq_handler(struct drm_device *dev,
 					 u32 hotplug_trigger,
 					 const u32 *hpd)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned long irqflags;
 	int i;
-	bool ret = false;
+	bool storm_detected = false;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
@@ -906,7 +903,7 @@ static inline bool intel_hpd_irq_handler(struct drm_device *dev,
 			dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
 			dev_priv->hpd_event_bits &= ~(1 << i);
 			DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
-			ret = true;
+			storm_detected = true;
 		} else {
 			dev_priv->hpd_stats[i].hpd_cnt++;
 		}
@@ -914,7 +911,8 @@ static inline bool intel_hpd_irq_handler(struct drm_device *dev,
 
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
-	return ret;
+	if (storm_detected)
+		dev_priv->display.hpd_irq_setup(dev);
 }
 
 static void gmbus_irq_handler(struct drm_device *dev)
@@ -1022,8 +1020,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 					 hotplug_status);
 			if (hotplug_trigger) {
-				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
-					i915_hpd_irq_setup(dev);
+				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 			}
@@ -1053,8 +1050,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
 	if (hotplug_trigger) {
-		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx))
-			ibx_hpd_irq_setup(dev);
+		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
@@ -1158,8 +1154,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
 	if (hotplug_trigger) {
-		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt))
-			ibx_hpd_irq_setup(dev);
+		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
@@ -3242,8 +3237,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
-					i915_hpd_irq_setup(dev);
+				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 			}
@@ -3488,9 +3482,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (intel_hpd_irq_handler(dev, hotplug_trigger,
-							    IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915))
-					i915_hpd_irq_setup(dev);
+				intel_hpd_irq_handler(dev, hotplug_trigger,
+						      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 			}
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 6/8] drm/i915: fold the queue_work into intel_hpd_irq_handler
  2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
                           ` (3 preceding siblings ...)
  2013-06-27 11:45         ` [PATCH 5/8] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler Daniel Vetter
@ 2013-06-27 11:45         ` Daniel Vetter
  2013-06-27 12:13           ` Chris Wilson
  2013-06-27 11:45         ` [PATCH 7/8] drm/i915: fold the no-irq check " Daniel Vetter
  2013-06-27 11:45         ` [PATCH 8/8] drm/i915: fix hpd interrupt register locking Daniel Vetter
  6 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 11:45 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

Everywhere the same.

v2: Rebase on top of the i965g/gm sdvo hpd fix.

Cc: Egbert Eich <eich@suse.de>
Reviewed-by: Egbert Eich <eich@suse.de>
Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 26c3127..58f7174 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -913,6 +913,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 
 	if (storm_detected)
 		dev_priv->display.hpd_irq_setup(dev);
+
+	queue_work(dev_priv->wq,
+		   &dev_priv->hotplug_work);
 }
 
 static void gmbus_irq_handler(struct drm_device *dev)
@@ -1021,8 +1024,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 					 hotplug_status);
 			if (hotplug_trigger) {
 				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-				queue_work(dev_priv->wq,
-					   &dev_priv->hotplug_work);
 			}
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
@@ -1051,7 +1052,6 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 
 	if (hotplug_trigger) {
 		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
-		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -1155,7 +1155,6 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 
 	if (hotplug_trigger) {
 		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
-		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -3238,8 +3237,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 				  hotplug_status);
 			if (hotplug_trigger) {
 				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-				queue_work(dev_priv->wq,
-					   &dev_priv->hotplug_work);
 			}
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			POSTING_READ(PORT_HOTPLUG_STAT);
@@ -3484,8 +3481,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			if (hotplug_trigger) {
 				intel_hpd_irq_handler(dev, hotplug_trigger,
 						      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
-				queue_work(dev_priv->wq,
-					   &dev_priv->hotplug_work);
 			}
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 7/8] drm/i915: fold the no-irq check into intel_hpd_irq_handler
  2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
                           ` (4 preceding siblings ...)
  2013-06-27 11:45         ` [PATCH 6/8] drm/i915: fold the queue_work " Daniel Vetter
@ 2013-06-27 11:45         ` Daniel Vetter
  2013-06-27 12:14           ` Chris Wilson
  2013-06-27 11:45         ` [PATCH 8/8] drm/i915: fix hpd interrupt register locking Daniel Vetter
  6 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 11:45 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

The usual pattern for our sub-function irq_handlers is that they check
for the no-irq case themselves. This results in more streamlined code
in the upper irq handlers.

v2: Rebase on top of the i965g/gm sdvo hpd fix.

Cc: Egbert Eich <eich@suse.de>
Reviewed-by: Egbert Eich <eich@suse.de>
Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 58f7174..95999bc 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -885,6 +885,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 	int i;
 	bool storm_detected = false;
 
+	if (!hotplug_trigger)
+		return;
+
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
 	for (i = 1; i < HPD_NUM_PINS; i++) {
@@ -1022,9 +1025,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 					 hotplug_status);
-			if (hotplug_trigger) {
-				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-			}
+
+			intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
 		}
@@ -1050,9 +1053,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 	int pipe;
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
-	if (hotplug_trigger) {
-		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
-	}
+	intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
+
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
 			       SDE_AUDIO_POWER_SHIFT);
@@ -1153,9 +1155,8 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 	int pipe;
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
-	if (hotplug_trigger) {
-		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
-	}
+	intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
+
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
 			       SDE_AUDIO_POWER_SHIFT_CPT);
@@ -3235,9 +3236,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
-			if (hotplug_trigger) {
-				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-			}
+
+			intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			POSTING_READ(PORT_HOTPLUG_STAT);
 		}
@@ -3478,10 +3479,10 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
-			if (hotplug_trigger) {
-				intel_hpd_irq_handler(dev, hotplug_trigger,
-						      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
-			}
+
+			intel_hpd_irq_handler(dev, hotplug_trigger,
+					      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
+
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
 		}
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 8/8] drm/i915: fix hpd interrupt register locking
  2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
                           ` (5 preceding siblings ...)
  2013-06-27 11:45         ` [PATCH 7/8] drm/i915: fold the no-irq check " Daniel Vetter
@ 2013-06-27 11:45         ` Daniel Vetter
  2013-06-27 14:41           ` Paulo Zanoni
  6 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 11:45 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

Our interrupt handler (in hardird context) could race with the timer
(in softirq context), hence we need to hold the spinlock around the
call to ->hdp_irq_setup in intel_hpd_irq_handler, too.

But as an optimization (and more so to clarify things) we don't need
to do the irqsave/restore dance in the hardirq context.

Note also that on ilk+ the race isn't just against the hotplug
reenable timer, but also against the fifo underrun reporting. That one
also modifies the SDEIMR register (again protected by the same
dev_priv->irq_lock).

To lock things down again sprinkle a assert_spin_locked. But exclude
the functions touching SDEIMR for now, I want to extract them all into
a new helper function (like we do already for pipestate, display
interrupts and all the various gt interrupts).

v2: Add the missing 't' Egbert spotted in a comment.

Cc: Egbert Eich <eich@suse.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 95999bc..6637575 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -881,15 +881,13 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 					 const u32 *hpd)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	unsigned long irqflags;
 	int i;
 	bool storm_detected = false;
 
 	if (!hotplug_trigger)
 		return;
 
-	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-
+	spin_lock(&dev_priv->irq_lock);
 	for (i = 1; i < HPD_NUM_PINS; i++) {
 
 		if (!(hpd[i] & hotplug_trigger) ||
@@ -912,10 +910,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 		}
 	}
 
-	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-
 	if (storm_detected)
 		dev_priv->display.hpd_irq_setup(dev);
+	spin_unlock(&dev_priv->irq_lock);
 
 	queue_work(dev_priv->wq,
 		   &dev_priv->hotplug_work);
@@ -2851,7 +2848,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 	I915_WRITE(PIPESTAT(1), 0xffff);
 	POSTING_READ(VLV_IER);
 
-	/* Interrup setup is already guaranteed to be single-threaded, this is
+	/* Interrupt setup is already guaranteed to be single-threaded, this is
 	 * just to make the assert_spin_locked check happy. */
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, 0, pipestat_enable);
@@ -3395,6 +3392,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
 	struct intel_encoder *intel_encoder;
 	u32 hotplug_en;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if (I915_HAS_HOTPLUG(dev)) {
 		hotplug_en = I915_READ(PORT_HOTPLUG_EN);
 		hotplug_en &= ~HOTPLUG_INT_EN_MASK;
@@ -3678,6 +3677,7 @@ void intel_hpd_init(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct drm_connector *connector;
+	unsigned long irqflags;
 	int i;
 
 	for (i = 1; i < HPD_NUM_PINS; i++) {
@@ -3690,6 +3690,11 @@ void intel_hpd_init(struct drm_device *dev)
 		if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
 			connector->polled = DRM_CONNECTOR_POLL_HPD;
 	}
+
+	/* Interrup setup is already guaranteed to be single-threaded, this is
+	 * just to make the assert_spin_locked checks happy. */
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	if (dev_priv->display.hpd_irq_setup)
 		dev_priv->display.hpd_irq_setup(dev);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* Re: [PATCH 6/8] drm/i915: fold the queue_work into intel_hpd_irq_handler
  2013-06-27 11:45         ` [PATCH 6/8] drm/i915: fold the queue_work " Daniel Vetter
@ 2013-06-27 12:13           ` Chris Wilson
  0 siblings, 0 replies; 86+ messages in thread
From: Chris Wilson @ 2013-06-27 12:13 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Egbert Eich, Intel Graphics Development

On Thu, Jun 27, 2013 at 01:45:03PM +0200, Daniel Vetter wrote:
> Everywhere the same.
> 
> v2: Rebase on top of the i965g/gm sdvo hpd fix.

Leaves surplus '{}' everywhere.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 7/8] drm/i915: fold the no-irq check into intel_hpd_irq_handler
  2013-06-27 11:45         ` [PATCH 7/8] drm/i915: fold the no-irq check " Daniel Vetter
@ 2013-06-27 12:14           ` Chris Wilson
  0 siblings, 0 replies; 86+ messages in thread
From: Chris Wilson @ 2013-06-27 12:14 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Egbert Eich, Intel Graphics Development

On Thu, Jun 27, 2013 at 01:45:04PM +0200, Daniel Vetter wrote:
> The usual pattern for our sub-function irq_handlers is that they check
> for the no-irq case themselves. This results in more streamlined code
> in the upper irq handlers.
> 
> v2: Rebase on top of the i965g/gm sdvo hpd fix.

And then the '{}' disappear here, meh.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 8/8] drm/i915: fix hpd interrupt register locking
  2013-06-27 11:45         ` [PATCH 8/8] drm/i915: fix hpd interrupt register locking Daniel Vetter
@ 2013-06-27 14:41           ` Paulo Zanoni
  2013-06-27 15:52             ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
  2013-06-27 17:44             ` [PATCH 8/8] drm/i915: fix hpd interrupt register locking Daniel Vetter
  0 siblings, 2 replies; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-27 14:41 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Egbert Eich, Intel Graphics Development

2013/6/27 Daniel Vetter <daniel.vetter@ffwll.ch>:
> Our interrupt handler (in hardird context) could race with the timer

s/hardird/hardirq/

> (in softirq context), hence we need to hold the spinlock around the
> call to ->hdp_irq_setup in intel_hpd_irq_handler, too.
>
> But as an optimization (and more so to clarify things) we don't need
> to do the irqsave/restore dance in the hardirq context.
>
> Note also that on ilk+ the race isn't just against the hotplug
> reenable timer, but also against the fifo underrun reporting. That one
> also modifies the SDEIMR register (again protected by the same
> dev_priv->irq_lock).
>
> To lock things down again sprinkle a assert_spin_locked. But exclude
> the functions touching SDEIMR for now, I want to extract them all into
> a new helper function (like we do already for pipestate, display
> interrupts and all the various gt interrupts).
>
> v2: Add the missing 't' Egbert spotted in a comment.
>
> Cc: Egbert Eich <eich@suse.de>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 17 +++++++++++------
>  1 file changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 95999bc..6637575 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -881,15 +881,13 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
>                                          const u32 *hpd)
>  {
>         drm_i915_private_t *dev_priv = dev->dev_private;
> -       unsigned long irqflags;
>         int i;
>         bool storm_detected = false;
>
>         if (!hotplug_trigger)
>                 return;
>
> -       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> -
> +       spin_lock(&dev_priv->irq_lock);
>         for (i = 1; i < HPD_NUM_PINS; i++) {
>
>                 if (!(hpd[i] & hotplug_trigger) ||
> @@ -912,10 +910,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
>                 }
>         }
>
> -       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> -
>         if (storm_detected)
>                 dev_priv->display.hpd_irq_setup(dev);
> +       spin_unlock(&dev_priv->irq_lock);
>
>         queue_work(dev_priv->wq,
>                    &dev_priv->hotplug_work);
> @@ -2851,7 +2848,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
>         I915_WRITE(PIPESTAT(1), 0xffff);
>         POSTING_READ(VLV_IER);
>
> -       /* Interrup setup is already guaranteed to be single-threaded, this is
> +       /* Interrupt setup is already guaranteed to be single-threaded, this is

Here you're fixing an error introduced in patch 03, instead of the
error pointed by Egbert.

>          * just to make the assert_spin_locked check happy. */
>         spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>         i915_enable_pipestat(dev_priv, 0, pipestat_enable);
> @@ -3395,6 +3392,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
>         struct intel_encoder *intel_encoder;
>         u32 hotplug_en;
>
> +       assert_spin_locked(&dev_priv->irq_lock);
> +
>         if (I915_HAS_HOTPLUG(dev)) {
>                 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
>                 hotplug_en &= ~HOTPLUG_INT_EN_MASK;
> @@ -3678,6 +3677,7 @@ void intel_hpd_init(struct drm_device *dev)
>         struct drm_i915_private *dev_priv = dev->dev_private;
>         struct drm_mode_config *mode_config = &dev->mode_config;
>         struct drm_connector *connector;
> +       unsigned long irqflags;
>         int i;
>
>         for (i = 1; i < HPD_NUM_PINS; i++) {
> @@ -3690,6 +3690,11 @@ void intel_hpd_init(struct drm_device *dev)
>                 if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
>                         connector->polled = DRM_CONNECTOR_POLL_HPD;
>         }
> +
> +       /* Interrup setup is already guaranteed to be single-threaded, this is

s/Interrup/Interrupt/



> +        * just to make the assert_spin_locked checks happy. */
> +       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>         if (dev_priv->display.hpd_irq_setup)
>                 dev_priv->display.hpd_irq_setup(dev);
> +       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
>  }
> --
> 1.8.1.4
>

So here's the review status for the 8 patches resent today:
- Patches 1 and 2: Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
- Patch 3: in two comments you need to s/Interrup/Interrupt/. Then you
can add Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
- Patches 4-7: You already have my Reviewed-by, but if you look in the
commit messages, some lines contain just my name and email, without
the "Reviewed-by:" text before them. I also wouldn't mind if you
resend patches 6 and 7 based on Chris's comments, but I don't really
care since the problem is actually solved in patch 7.
- Patch 8: due to the change you'll do in patch 3, you'll have to redo
patch 8. If you fix both the "Interrup" and the "hardird" typo you can
also add Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

I also booted a Haswell with these new patches and after 120 seconds
of uptime I don't see any new WARNs or ERRORs.

-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable
  2013-06-27 14:41           ` Paulo Zanoni
@ 2013-06-27 15:52             ` Daniel Vetter
  2013-06-27 15:52               ` [PATCH 2/6] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
                                 ` (5 more replies)
  2013-06-27 17:44             ` [PATCH 8/8] drm/i915: fix hpd interrupt register locking Daniel Vetter
  1 sibling, 6 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 15:52 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Just to keep the paranoia equal also sprinkle locking asserts over the
pipestat interrupt enable/disable functions.

Again this results in false positives in the interrupt setup. Add
bogo-locking for these and a big comment explaining why it's there and
that it's indeed unnecessary.

v2: Fix up the spelling fail Paulo spotted in comments.

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 465588f..e7c879b 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -322,6 +322,8 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 	u32 reg = PIPESTAT(pipe);
 	u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((pipestat & mask) == mask)
 		return;
 
@@ -337,6 +339,8 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 	u32 reg = PIPESTAT(pipe);
 	u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if ((pipestat & mask) == 0)
 		return;
 
@@ -2826,6 +2830,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 	u32 gt_irqs;
 	u32 enable_mask;
 	u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
+	unsigned long irqflags;
 
 	enable_mask = I915_DISPLAY_PORT_INTERRUPT;
 	enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
@@ -2851,9 +2856,13 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 	I915_WRITE(PIPESTAT(1), 0xffff);
 	POSTING_READ(VLV_IER);
 
+	/* Interrupt setup is already guaranteed to be single-threaded, this is
+	 * just to make the assert_spin_locked check happy. */
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, 0, pipestat_enable);
 	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
 	i915_enable_pipestat(dev_priv, 1, pipestat_enable);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
 	I915_WRITE(VLV_IIR, 0xffffffff);
 	I915_WRITE(VLV_IIR, 0xffffffff);
@@ -3335,6 +3344,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	u32 enable_mask;
 	u32 error_mask;
+	unsigned long irqflags;
 
 	/* Unmask the interrupts that we always want on. */
 	dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
@@ -3353,7 +3363,11 @@ static int i965_irq_postinstall(struct drm_device *dev)
 	if (IS_G4X(dev))
 		enable_mask |= I915_BSD_USER_INTERRUPT;
 
+	/* Interrupt setup is already guaranteed to be single-threaded, this is
+	 * just to make the assert_spin_locked check happy. */
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
 	/*
 	 * Enable some error detection, note the instruction error mask
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 2/6] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/
  2013-06-27 15:52             ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
@ 2013-06-27 15:52               ` Daniel Vetter
  2013-06-27 15:52               ` [PATCH 3/6] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler Daniel Vetter
                                 ` (4 subsequent siblings)
  5 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 15:52 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

The combination of Paulo's fifo underrun detection code and Egbert's
hpd storm handling code unfortunately made the hpd storm handling code
racy.

To avoid duplicating tricky interrupt locking code over all platforms
start with a bit of refactoring. This patch is the very first step
since in the end the irq storm handling code will handle all hotplug
logic (and so also encapsulate the locking nicely).

v2: Rebase on top of the i965g/gm sdvo hpd fix.

Cc: Egbert Eich <eich@suse.de>
Reviewed-by: Egbert Eich <eich@suse.de>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index e7c879b..2d0d786 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -879,9 +879,9 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
 #define HPD_STORM_DETECT_PERIOD 1000
 #define HPD_STORM_THRESHOLD 5
 
-static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
-					    u32 hotplug_trigger,
-					    const u32 *hpd)
+static inline bool intel_hpd_irq_handler(struct drm_device *dev,
+					 u32 hotplug_trigger,
+					 const u32 *hpd)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned long irqflags;
@@ -1022,7 +1022,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 					 hotplug_status);
 			if (hotplug_trigger) {
-				if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
 					i915_hpd_irq_setup(dev);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
@@ -1053,7 +1053,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
 	if (hotplug_trigger) {
-		if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx))
+		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx))
 			ibx_hpd_irq_setup(dev);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
@@ -1158,7 +1158,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
 	if (hotplug_trigger) {
-		if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt))
+		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt))
 			ibx_hpd_irq_setup(dev);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
@@ -3242,7 +3242,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
+				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
 					i915_hpd_irq_setup(dev);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
@@ -3488,7 +3488,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (hotplug_irq_storm_detect(dev, hotplug_trigger,
+				if (intel_hpd_irq_handler(dev, hotplug_trigger,
 							    IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915))
 					i915_hpd_irq_setup(dev);
 				queue_work(dev_priv->wq,
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 3/6] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler
  2013-06-27 15:52             ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
  2013-06-27 15:52               ` [PATCH 2/6] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
@ 2013-06-27 15:52               ` Daniel Vetter
  2013-06-27 15:52               ` [PATCH 4/6] drm/i915: fold the queue_work " Daniel Vetter
                                 ` (3 subsequent siblings)
  5 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 15:52 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

We already have a vfunc for this (and other parts of the hpd storm
handling code already use it).

v2: Rebase on top of the i965g/gm sdvo hpd fix.

Cc: Egbert Eich <eich@suse.de>
Reviewed-by: Egbert Eich <eich@suse.de>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 2d0d786..b9e6628 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -79,9 +79,6 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
 };
 
-static void ibx_hpd_irq_setup(struct drm_device *dev);
-static void i915_hpd_irq_setup(struct drm_device *dev);
-
 /* For display hotplug interrupt */
 static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
@@ -879,14 +876,14 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
 #define HPD_STORM_DETECT_PERIOD 1000
 #define HPD_STORM_THRESHOLD 5
 
-static inline bool intel_hpd_irq_handler(struct drm_device *dev,
+static inline void intel_hpd_irq_handler(struct drm_device *dev,
 					 u32 hotplug_trigger,
 					 const u32 *hpd)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned long irqflags;
 	int i;
-	bool ret = false;
+	bool storm_detected = false;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
@@ -906,7 +903,7 @@ static inline bool intel_hpd_irq_handler(struct drm_device *dev,
 			dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
 			dev_priv->hpd_event_bits &= ~(1 << i);
 			DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
-			ret = true;
+			storm_detected = true;
 		} else {
 			dev_priv->hpd_stats[i].hpd_cnt++;
 		}
@@ -914,7 +911,8 @@ static inline bool intel_hpd_irq_handler(struct drm_device *dev,
 
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
-	return ret;
+	if (storm_detected)
+		dev_priv->display.hpd_irq_setup(dev);
 }
 
 static void gmbus_irq_handler(struct drm_device *dev)
@@ -1022,8 +1020,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 					 hotplug_status);
 			if (hotplug_trigger) {
-				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
-					i915_hpd_irq_setup(dev);
+				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 			}
@@ -1053,8 +1050,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
 	if (hotplug_trigger) {
-		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx))
-			ibx_hpd_irq_setup(dev);
+		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
@@ -1158,8 +1154,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
 	if (hotplug_trigger) {
-		if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt))
-			ibx_hpd_irq_setup(dev);
+		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
@@ -3242,8 +3237,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915))
-					i915_hpd_irq_setup(dev);
+				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 			}
@@ -3488,9 +3482,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
 			if (hotplug_trigger) {
-				if (intel_hpd_irq_handler(dev, hotplug_trigger,
-							    IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915))
-					i915_hpd_irq_setup(dev);
+				intel_hpd_irq_handler(dev, hotplug_trigger,
+						      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
 				queue_work(dev_priv->wq,
 					   &dev_priv->hotplug_work);
 			}
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 4/6] drm/i915: fold the queue_work into intel_hpd_irq_handler
  2013-06-27 15:52             ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
  2013-06-27 15:52               ` [PATCH 2/6] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
  2013-06-27 15:52               ` [PATCH 3/6] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler Daniel Vetter
@ 2013-06-27 15:52               ` Daniel Vetter
  2013-06-27 15:52               ` [PATCH 5/6] drm/i915: fold the no-irq check " Daniel Vetter
                                 ` (2 subsequent siblings)
  5 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 15:52 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

Everywhere the same.

Note that this patch leaves unnecessary braces behind, but the next
patch will kill those all anyway (including the if itself) so I've
figured I can keep the diff a bit smaller.

v2: Rebase on top of the i965g/gm sdvo hpd fix.

Cc: Egbert Eich <eich@suse.de>
Reviewed-by: Egbert Eich <eich@suse.de>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b9e6628..cfe280e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -913,6 +913,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 
 	if (storm_detected)
 		dev_priv->display.hpd_irq_setup(dev);
+
+	queue_work(dev_priv->wq,
+		   &dev_priv->hotplug_work);
 }
 
 static void gmbus_irq_handler(struct drm_device *dev)
@@ -1021,8 +1024,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 					 hotplug_status);
 			if (hotplug_trigger) {
 				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-				queue_work(dev_priv->wq,
-					   &dev_priv->hotplug_work);
 			}
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
@@ -1051,7 +1052,6 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 
 	if (hotplug_trigger) {
 		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
-		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -1155,7 +1155,6 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 
 	if (hotplug_trigger) {
 		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
-		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
 	}
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -3238,8 +3237,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 				  hotplug_status);
 			if (hotplug_trigger) {
 				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-				queue_work(dev_priv->wq,
-					   &dev_priv->hotplug_work);
 			}
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			POSTING_READ(PORT_HOTPLUG_STAT);
@@ -3484,8 +3481,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			if (hotplug_trigger) {
 				intel_hpd_irq_handler(dev, hotplug_trigger,
 						      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
-				queue_work(dev_priv->wq,
-					   &dev_priv->hotplug_work);
 			}
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 5/6] drm/i915: fold the no-irq check into intel_hpd_irq_handler
  2013-06-27 15:52             ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
                                 ` (2 preceding siblings ...)
  2013-06-27 15:52               ` [PATCH 4/6] drm/i915: fold the queue_work " Daniel Vetter
@ 2013-06-27 15:52               ` Daniel Vetter
  2013-06-27 15:52               ` [PATCH 6/6] drm/i915: fix hpd interrupt register locking Daniel Vetter
  2013-07-04 19:22               ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
  5 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 15:52 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

The usual pattern for our sub-function irq_handlers is that they check
for the no-irq case themselves. This results in more streamlined code
in the upper irq handlers.

v2: Rebase on top of the i965g/gm sdvo hpd fix.

Cc: Egbert Eich <eich@suse.de>
Reviewed-by: Egbert Eich <eich@suse.de>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index cfe280e..a924f72 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -885,6 +885,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 	int i;
 	bool storm_detected = false;
 
+	if (!hotplug_trigger)
+		return;
+
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
 	for (i = 1; i < HPD_NUM_PINS; i++) {
@@ -1022,9 +1025,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 					 hotplug_status);
-			if (hotplug_trigger) {
-				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-			}
+
+			intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
 		}
@@ -1050,9 +1053,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 	int pipe;
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
-	if (hotplug_trigger) {
-		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
-	}
+	intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
+
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
 			       SDE_AUDIO_POWER_SHIFT);
@@ -1153,9 +1155,8 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 	int pipe;
 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
-	if (hotplug_trigger) {
-		intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
-	}
+	intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
+
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
 			       SDE_AUDIO_POWER_SHIFT_CPT);
@@ -3235,9 +3236,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
-			if (hotplug_trigger) {
-				intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-			}
+
+			intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			POSTING_READ(PORT_HOTPLUG_STAT);
 		}
@@ -3478,10 +3479,10 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 				  hotplug_status);
-			if (hotplug_trigger) {
-				intel_hpd_irq_handler(dev, hotplug_trigger,
-						      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
-			}
+
+			intel_hpd_irq_handler(dev, hotplug_trigger,
+					      IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
+
 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 			I915_READ(PORT_HOTPLUG_STAT);
 		}
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* [PATCH 6/6] drm/i915: fix hpd interrupt register locking
  2013-06-27 15:52             ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
                                 ` (3 preceding siblings ...)
  2013-06-27 15:52               ` [PATCH 5/6] drm/i915: fold the no-irq check " Daniel Vetter
@ 2013-06-27 15:52               ` Daniel Vetter
  2013-07-04 19:22               ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
  5 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 15:52 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Egbert Eich, Daniel Vetter

Our interrupt handler (in hardirq context) could race with the timer
(in softirq context), hence we need to hold the spinlock around the
call to ->hdp_irq_setup in intel_hpd_irq_handler, too.

But as an optimization (and more so to clarify things) we don't need
to do the irqsave/restore dance in the hardirq context.

Note also that on ilk+ the race isn't just against the hotplug
reenable timer, but also against the fifo underrun reporting. That one
also modifies the SDEIMR register (again protected by the same
dev_priv->irq_lock).

To lock things down again sprinkle a assert_spin_locked. But exclude
the functions touching SDEIMR for now, I want to extract them all into
a new helper function (like we do already for pipestate, display
interrupts and all the various gt interrupts).

v2: Add the missing 't' Egbert spotted in a comment.

v3: Actually fix the right misspelled comment (Paulo).

Cc: Egbert Eich <eich@suse.de>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_irq.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index a924f72..9f3d65b 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -881,15 +881,13 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 					 const u32 *hpd)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	unsigned long irqflags;
 	int i;
 	bool storm_detected = false;
 
 	if (!hotplug_trigger)
 		return;
 
-	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-
+	spin_lock(&dev_priv->irq_lock);
 	for (i = 1; i < HPD_NUM_PINS; i++) {
 
 		if (!(hpd[i] & hotplug_trigger) ||
@@ -912,10 +910,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 		}
 	}
 
-	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-
 	if (storm_detected)
 		dev_priv->display.hpd_irq_setup(dev);
+	spin_unlock(&dev_priv->irq_lock);
 
 	queue_work(dev_priv->wq,
 		   &dev_priv->hotplug_work);
@@ -3395,6 +3392,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
 	struct intel_encoder *intel_encoder;
 	u32 hotplug_en;
 
+	assert_spin_locked(&dev_priv->irq_lock);
+
 	if (I915_HAS_HOTPLUG(dev)) {
 		hotplug_en = I915_READ(PORT_HOTPLUG_EN);
 		hotplug_en &= ~HOTPLUG_INT_EN_MASK;
@@ -3678,6 +3677,7 @@ void intel_hpd_init(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct drm_connector *connector;
+	unsigned long irqflags;
 	int i;
 
 	for (i = 1; i < HPD_NUM_PINS; i++) {
@@ -3690,6 +3690,11 @@ void intel_hpd_init(struct drm_device *dev)
 		if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
 			connector->polled = DRM_CONNECTOR_POLL_HPD;
 	}
+
+	/* Interrupt setup is already guaranteed to be single-threaded, this is
+	 * just to make the assert_spin_locked checks happy. */
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	if (dev_priv->display.hpd_irq_setup)
 		dev_priv->display.hpd_irq_setup(dev);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 86+ messages in thread

* Re: [PATCH 8/8] drm/i915: fix hpd interrupt register locking
  2013-06-27 14:41           ` Paulo Zanoni
  2013-06-27 15:52             ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
@ 2013-06-27 17:44             ` Daniel Vetter
  1 sibling, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 17:44 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Egbert Eich, Daniel Vetter, Intel Graphics Development

On Thu, Jun 27, 2013 at 11:41:25AM -0300, Paulo Zanoni wrote:
> 2013/6/27 Daniel Vetter <daniel.vetter@ffwll.ch>:
> > Our interrupt handler (in hardird context) could race with the timer
> 
> s/hardird/hardirq/
> 
> > (in softirq context), hence we need to hold the spinlock around the
> > call to ->hdp_irq_setup in intel_hpd_irq_handler, too.
> >
> > But as an optimization (and more so to clarify things) we don't need
> > to do the irqsave/restore dance in the hardirq context.
> >
> > Note also that on ilk+ the race isn't just against the hotplug
> > reenable timer, but also against the fifo underrun reporting. That one
> > also modifies the SDEIMR register (again protected by the same
> > dev_priv->irq_lock).
> >
> > To lock things down again sprinkle a assert_spin_locked. But exclude
> > the functions touching SDEIMR for now, I want to extract them all into
> > a new helper function (like we do already for pipestate, display
> > interrupts and all the various gt interrupts).
> >
> > v2: Add the missing 't' Egbert spotted in a comment.
> >
> > Cc: Egbert Eich <eich@suse.de>
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/i915_irq.c | 17 +++++++++++------
> >  1 file changed, 11 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index 95999bc..6637575 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -881,15 +881,13 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
> >                                          const u32 *hpd)
> >  {
> >         drm_i915_private_t *dev_priv = dev->dev_private;
> > -       unsigned long irqflags;
> >         int i;
> >         bool storm_detected = false;
> >
> >         if (!hotplug_trigger)
> >                 return;
> >
> > -       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> > -
> > +       spin_lock(&dev_priv->irq_lock);
> >         for (i = 1; i < HPD_NUM_PINS; i++) {
> >
> >                 if (!(hpd[i] & hotplug_trigger) ||
> > @@ -912,10 +910,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
> >                 }
> >         }
> >
> > -       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> > -
> >         if (storm_detected)
> >                 dev_priv->display.hpd_irq_setup(dev);
> > +       spin_unlock(&dev_priv->irq_lock);
> >
> >         queue_work(dev_priv->wq,
> >                    &dev_priv->hotplug_work);
> > @@ -2851,7 +2848,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
> >         I915_WRITE(PIPESTAT(1), 0xffff);
> >         POSTING_READ(VLV_IER);
> >
> > -       /* Interrup setup is already guaranteed to be single-threaded, this is
> > +       /* Interrupt setup is already guaranteed to be single-threaded, this is
> 
> Here you're fixing an error introduced in patch 03, instead of the
> error pointed by Egbert.
> 
> >          * just to make the assert_spin_locked check happy. */
> >         spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> >         i915_enable_pipestat(dev_priv, 0, pipestat_enable);
> > @@ -3395,6 +3392,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
> >         struct intel_encoder *intel_encoder;
> >         u32 hotplug_en;
> >
> > +       assert_spin_locked(&dev_priv->irq_lock);
> > +
> >         if (I915_HAS_HOTPLUG(dev)) {
> >                 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
> >                 hotplug_en &= ~HOTPLUG_INT_EN_MASK;
> > @@ -3678,6 +3677,7 @@ void intel_hpd_init(struct drm_device *dev)
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> >         struct drm_mode_config *mode_config = &dev->mode_config;
> >         struct drm_connector *connector;
> > +       unsigned long irqflags;
> >         int i;
> >
> >         for (i = 1; i < HPD_NUM_PINS; i++) {
> > @@ -3690,6 +3690,11 @@ void intel_hpd_init(struct drm_device *dev)
> >                 if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
> >                         connector->polled = DRM_CONNECTOR_POLL_HPD;
> >         }
> > +
> > +       /* Interrup setup is already guaranteed to be single-threaded, this is
> 
> s/Interrup/Interrupt/
> 
> 
> 
> > +        * just to make the assert_spin_locked checks happy. */
> > +       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> >         if (dev_priv->display.hpd_irq_setup)
> >                 dev_priv->display.hpd_irq_setup(dev);
> > +       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> >  }
> > --
> > 1.8.1.4
> >
> 
> So here's the review status for the 8 patches resent today:
> - Patches 1 and 2: Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> - Patch 3: in two comments you need to s/Interrup/Interrupt/. Then you
> can add Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> - Patches 4-7: You already have my Reviewed-by, but if you look in the
> commit messages, some lines contain just my name and email, without
> the "Reviewed-by:" text before them. I also wouldn't mind if you
> resend patches 6 and 7 based on Chris's comments, but I don't really
> care since the problem is actually solved in patch 7.
> - Patch 8: due to the change you'll do in patch 3, you'll have to redo
> patch 8. If you fix both the "Interrup" and the "hardird" typo you can
> also add Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> 
> I also booted a Haswell with these new patches and after 120 seconds
> of uptime I don't see any new WARNs or ERRORs.

Ok, I've merged the first 8 patches from this series, thanks for the
review.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 10/24] drm/i915: remove SERR_INT clearing in the postinstall hook
  2013-06-12 11:37 ` [PATCH 10/24] drm/i915: remove SERR_INT clearing in the postinstall hook Daniel Vetter
@ 2013-06-27 19:34   ` Paulo Zanoni
  2013-07-04 19:49     ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-27 19:34 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

2013/6/12 Daniel Vetter <daniel.vetter@ffwll.ch>:
> The preinstallhook is supposed to clear all interrupts. Doing it
> again in the postinstall hook has the risk that we're eating
> an interrupt source from the handler. If that happens too often,
> the kernel will disable our interrupt handler.

We do this with other registers too, why not remove those bits too
then? I mean, SERR_INT is just like one of the IIR interrupts, and we
always clear the IIR registers on postinstall functions. Can you
please explain a little bit more?


>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 2 --
>  1 file changed, 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index c2b4b09..685ad84 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2635,8 +2635,6 @@ static void ibx_irq_postinstall(struct drm_device *dev)
>                        SDE_TRANSA_FIFO_UNDER | SDE_POISON;
>         } else {
>                 mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
> -
> -               I915_WRITE(SERR_INT, I915_READ(SERR_INT));
>         }
>
>         I915_WRITE(SDEIIR, I915_READ(SDEIIR));
> --
> 1.8.1.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 11/24] drm/i915: improve SERR_INT clearing for fifo underrun reporting
  2013-06-12 11:37 ` [PATCH 11/24] drm/i915: improve SERR_INT clearing for fifo underrun reporting Daniel Vetter
@ 2013-06-27 20:19   ` Paulo Zanoni
  2013-07-04 19:55     ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-27 20:19 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

2013/6/12 Daniel Vetter <daniel.vetter@ffwll.ch>:
> The current code won't report any fifo underruns on cpt if just one
> pipe has fifo underrun reporting disabled. We can't enable the
> interrupts, but we can still check the per-transcoder bits and so
> report the underrun delayed if:
> - We always clear the transcoder's bit (and none of the other bits)
>   when enabling.
> - We check the transcoder's bit after disabling (to avoid racing with
>   the interrupt handler).

I guess you'll have to update this patch due to my bikeshed on IRC for
patch 9. Anyway, comments below:


>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 15 +++++++++++----
>  drivers/gpu/drm/i915/i915_reg.h |  1 +
>  2 files changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 685ad84..8627043 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -210,16 +210,23 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
>         struct drm_i915_private *dev_priv = dev->dev_private;
>
>         if (enable) {
> +               I915_WRITE(SERR_INT,
> +                          SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
> +
>                 if (!cpt_can_enable_serr_int(dev))
>                         return;
> -
> -               I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN |
> -                                    SERR_INT_TRANS_B_FIFO_UNDERRUN |
> -                                    SERR_INT_TRANS_C_FIFO_UNDERRUN);
>         }
>
>         ibx_display_interrupt_update(dev_priv, SDE_ERROR_CPT,
>                                      enable ? SDE_ERROR_CPT : 0);
> +
> +       if (!enable) {
> +               uint32_t tmp = I915_READ(SERR_INT);
> +
> +               if (tmp & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder))
> +                       DRM_DEBUG_KMS("uncleared pch fifo underrun on pipe %i\n",
> +                                     pch_transcoder);

Use %c and transcoder_name(pch_transcoder), otherwise you trigger
people's OCDs again :)

Also, I think the logic in this patch is inverted.

Imagine everything is running correctly and the bits are all in the
ideal state. Then we get an underrun report on transcoder A. We'll
detect this inside cpt_serr_int_handler, call
intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false), which
will call cpt_set_fifo_underrun_reporting(dev, TRANSCODER_A, false).
Then, inside your cpt_set_fifo_underrun_reporting, we'll disable
SDE_ERROR_CPT, then read SERR_INT, see that the bit is 1 and print the
DRM_DEBUG_KMS message you added. We'll return from
cpt_set_fifo_underrun_reporting, then return from
intel_set_pch_fifo_underrun_reporting, and then we'll print an error
message again inside cpt_serr_int_handler. So we'll print 2 messages
for a single underrun.

Instead of checking if the bit is 1 before disabling it, you should
check if the bit is 1 before re-enabling it. The problem that you're
trying to fix is that we don't report underruns while SDE_ERROR_CPT is
disabled, so the solution is to ask "did we get any underruns while
SDE_ERROR_CPT was disabled?", so inside the "if (enable)" case we need
to check if the bit was 1, and on the "if (!enable)" case we need to
clear the bit. Also, we should probably only print this "undetected
pch fifo underrun" message if crtc->pch_fifo_underrun_disabled is
false (otherwise we may report underruns on the same pipe multiple
times).

I hope I'm not confused :)


> +       }
>  }
>
>  /**
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index b1fdca9..86e3987 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -3880,6 +3880,7 @@
>  #define  SERR_INT_TRANS_C_FIFO_UNDERRUN        (1<<6)
>  #define  SERR_INT_TRANS_B_FIFO_UNDERRUN        (1<<3)
>  #define  SERR_INT_TRANS_A_FIFO_UNDERRUN        (1<<0)
> +#define  SERR_INT_TRANS_FIFO_UNDERRUN(pipe)    (1<< (pipe*3))
>
>  /* digital port hotplug */
>  #define PCH_PORT_HOTPLUG        0xc4030                /* SHOTPLUG_CTL */
> --
> 1.8.1.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns
  2013-06-12 14:46     ` [PATCH] " Daniel Vetter
@ 2013-06-27 20:45       ` Paulo Zanoni
  2013-07-04 20:41         ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-27 20:45 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

2013/6/12 Daniel Vetter <daniel.vetter@ffwll.ch>:
> It's racy: There's no guarantee that we won't walk this code (due to a
> pch fifo underrun interrupt) while someone is changing the pointers
> around.

Can you please exemplify the "someone is changing the pointers around"
case? I need to make sure I fully understand this.


>
> The only reason we do this is to use the righ crtc for the pch fifo
> underrun accounting. But we never expose this to userspace, so
> essentially no one really cares if we use the "wrong" crtc.
>
> So let's just rip it out.
>
> With this patch fifo underrun code will always use crtc A for tracking
> underruns on the (only) pch transcoder on LPT.
>
> v2: Add a big comment explaining what's going on. Requested by Paulo.
>
> Cc: Paulo Zanoni <przanoni@gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++-------------------------
>  1 file changed, 15 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index bb26555..e80c610 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -193,13 +193,13 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
>         POSTING_READ(SDEIMR);
>  }
>
> -static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
> +static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
> +                                           enum transcoder pch_transcoder,
>                                             bool enable)
>  {
> -       struct drm_device *dev = crtc->base.dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> -       uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
> -                                               SDE_TRANSB_FIFO_UNDER;
> +       uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
> +                      SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
>
>         ibx_display_interrupt_update(dev_priv, bit,
>                                      enable ? bit : 0);
> @@ -292,29 +292,19 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
>                                            bool enable)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
> -       enum pipe p;
> -       struct drm_crtc *crtc;
> -       struct intel_crtc *intel_crtc;
> +       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
> +       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>         unsigned long flags;
>         bool ret;
>
> -       if (HAS_PCH_LPT(dev)) {
> -               crtc = NULL;
> -               for_each_pipe(p) {
> -                       struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p];
> -                       if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) {
> -                               crtc = c;
> -                               break;
> -                       }
> -               }
> -               if (!crtc) {
> -                       DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n");
> -                       return false;
> -               }
> -       } else {
> -               crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
> -       }
> -       intel_crtc = to_intel_crtc(crtc);
> +       /*
> +        * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
> +        * has has only one pch transcoder A that all pipes can use. To avoid

s/has has/has/

> +        * racy pch transcoder -> pipe lookups from interrupt code simply store
> +        * the underrun statistics in crtc A. Since we never expose this
> +        * anywhere nor use it outside of the fifo underrun code here using the

We do expose it to the user as an error message. On Haswell we call
cpt_set_fifo_underrun_reporting, and you recently added a message
there saying "uncleared pch fifo underrun on pipe %i". This is wrong
since we'll always print "pipe A" on Haswell. If we reword the error
message to say "on PCH transcoder A" then we'll be always correct.


> +        * "wrong" crtc on LPT won't cause issues.
> +        */
>
>         spin_lock_irqsave(&dev_priv->irq_lock, flags);
>
> @@ -326,7 +316,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
>         intel_crtc->pch_fifo_underrun_disabled = !enable;
>
>         if (HAS_PCH_IBX(dev))
> -               ibx_set_fifo_underrun_reporting(intel_crtc, enable);
> +               ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
>         else
>                 cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
>
> --
> 1.8.1.4
>



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH] drm/i915: irq handlers don't need interrupt-safe spinlocks
  2013-06-25 12:27   ` [PATCH] " Daniel Vetter
@ 2013-06-27 21:14     ` Paulo Zanoni
  2013-06-27 22:40       ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-27 21:14 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

2013/6/25 Daniel Vetter <daniel.vetter@ffwll.ch>:
> Since we only have one interrupt handler and interrupt handlers are
> non-reentrant.
>
> To drive the point really home give them all an _irq_handler suffix.

Could we also add WARN(!in_irq()) or something equivalent for better
protection? Big backtraces are a nice way to discover we did something
wrong.

Besides the suggestion, the patch looks correct.

>
> This is a tiny micro-optimization but even more important it makes it
> clearer what locking we actually need. And in case someone screws this
> up: lockdep will catch hardirq vs. other context deadlocks.
>
> v2: Fix up compile fail.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 42 ++++++++++++++++++-----------------------
>  1 file changed, 18 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 3e6524a..6906b0f 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -646,14 +646,13 @@ static void i915_hotplug_work_func(struct work_struct *work)
>                 drm_kms_helper_hotplug_event(dev);
>  }
>
> -static void ironlake_handle_rps_change(struct drm_device *dev)
> +static void ironlake_rps_change_irq_handler(struct drm_device *dev)
>  {
>         drm_i915_private_t *dev_priv = dev->dev_private;
>         u32 busy_up, busy_down, max_avg, min_avg;
>         u8 new_delay;
> -       unsigned long flags;
>
> -       spin_lock_irqsave(&mchdev_lock, flags);
> +       spin_lock(&mchdev_lock);
>
>         I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
>
> @@ -681,7 +680,7 @@ static void ironlake_handle_rps_change(struct drm_device *dev)
>         if (ironlake_set_drps(dev, new_delay))
>                 dev_priv->ips.cur_delay = new_delay;
>
> -       spin_unlock_irqrestore(&mchdev_lock, flags);
> +       spin_unlock(&mchdev_lock);
>
>         return;
>  }
> @@ -817,18 +816,17 @@ static void ivybridge_parity_work(struct work_struct *work)
>         kfree(parity_event[1]);
>  }
>
> -static void ivybridge_handle_parity_error(struct drm_device *dev)
> +static void ivybridge_parity_error_irq_handler(struct drm_device *dev)
>  {
>         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> -       unsigned long flags;
>
>         if (!HAS_L3_GPU_CACHE(dev))
>                 return;
>
> -       spin_lock_irqsave(&dev_priv->irq_lock, flags);
> +       spin_lock(&dev_priv->irq_lock);
>         dev_priv->gt_irq_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
>         I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
> -       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
> +       spin_unlock(&dev_priv->irq_lock);
>
>         queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
>  }
> @@ -854,15 +852,13 @@ static void snb_gt_irq_handler(struct drm_device *dev,
>         }
>
>         if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
> -               ivybridge_handle_parity_error(dev);
> +               ivybridge_parity_error_irq_handler(dev);
>  }
>
>  /* Legacy way of handling PM interrupts */
> -static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
> -                               u32 pm_iir)
> +static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv,
> +                                u32 pm_iir)
>  {
> -       unsigned long flags;
> -
>         /*
>          * IIR bits should never already be set because IMR should
>          * prevent an interrupt from being shown in IIR. The warning
> @@ -873,11 +869,11 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
>          * The mask bit in IMR is cleared by dev_priv->rps.work.
>          */
>
> -       spin_lock_irqsave(&dev_priv->rps.lock, flags);
> +       spin_lock(&dev_priv->rps.lock);
>         dev_priv->rps.pm_iir |= pm_iir;
>         I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
>         POSTING_READ(GEN6_PMIMR);
> -       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
> +       spin_unlock(&dev_priv->rps.lock);
>
>         queue_work(dev_priv->wq, &dev_priv->rps.work);
>  }
> @@ -941,7 +937,7 @@ static void dp_aux_irq_handler(struct drm_device *dev)
>         wake_up_all(&dev_priv->gmbus_wait_queue);
>  }
>
> -/* Unlike gen6_queue_rps_work() from which this function is originally derived,
> +/* Unlike gen6_rps_irq_handler() from which this function is originally derived,
>   * we must be able to deal with other PM interrupts. This is complicated because
>   * of the way in which we use the masks to defer the RPS work (which for
>   * posterity is necessary because of forcewake).
> @@ -949,9 +945,7 @@ static void dp_aux_irq_handler(struct drm_device *dev)
>  static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
>                                u32 pm_iir)
>  {
> -       unsigned long flags;
> -
> -       spin_lock_irqsave(&dev_priv->rps.lock, flags);
> +       spin_lock(&dev_priv->rps.lock);
>         dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
>         if (dev_priv->rps.pm_iir) {
>                 I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
> @@ -960,7 +954,7 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
>                 /* TODO: if queue_work is slow, move it out of the spinlock */
>                 queue_work(dev_priv->wq, &dev_priv->rps.work);
>         }
> -       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
> +       spin_unlock(&dev_priv->rps.lock);
>
>         if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
>                 if (pm_iir & PM_VEBOX_USER_INTERRUPT)
> @@ -1042,7 +1036,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
>                         gmbus_irq_handler(dev);
>
>                 if (pm_iir & GEN6_PM_RPS_EVENTS)
> -                       gen6_queue_rps_work(dev_priv, pm_iir);
> +                       gen6_rps_irq_handler(dev_priv, pm_iir);
>
>                 I915_WRITE(GTIIR, gt_iir);
>                 I915_WRITE(GEN6_PMIIR, pm_iir);
> @@ -1280,7 +1274,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>                 if (IS_HASWELL(dev))
>                         hsw_pm_irq_handler(dev_priv, pm_iir);
>                 else if (pm_iir & GEN6_PM_RPS_EVENTS)
> -                       gen6_queue_rps_work(dev_priv, pm_iir);
> +                       gen6_rps_irq_handler(dev_priv, pm_iir);
>                 I915_WRITE(GEN6_PMIIR, pm_iir);
>                 ret = IRQ_HANDLED;
>         }
> @@ -1397,10 +1391,10 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
>         }
>
>         if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT)
> -               ironlake_handle_rps_change(dev);
> +               ironlake_rps_change_irq_handler(dev);
>
>         if (IS_GEN6(dev) && pm_iir & GEN6_PM_RPS_EVENTS)
> -               gen6_queue_rps_work(dev_priv, pm_iir);
> +               gen6_rps_irq_handler(dev_priv, pm_iir);
>
>         I915_WRITE(GTIIR, gt_iir);
>         I915_WRITE(DEIIR, de_iir);
> --
> 1.8.1.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH] drm/i915: irq handlers don't need interrupt-safe spinlocks
  2013-06-27 21:14     ` Paulo Zanoni
@ 2013-06-27 22:40       ` Daniel Vetter
  2013-06-28 16:57         ` Paulo Zanoni
  0 siblings, 1 reply; 86+ messages in thread
From: Daniel Vetter @ 2013-06-27 22:40 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development

On Thu, Jun 27, 2013 at 11:14 PM, Paulo Zanoni <przanoni@gmail.com> wrote:
> 2013/6/25 Daniel Vetter <daniel.vetter@ffwll.ch>:
>> Since we only have one interrupt handler and interrupt handlers are
>> non-reentrant.
>>
>> To drive the point really home give them all an _irq_handler suffix.
>
> Could we also add WARN(!in_irq()) or something equivalent for better
> protection? Big backtraces are a nice way to discover we did something
> wrong.

Lockdep checks hard/soft irq context constraints and will scream
horribly into dmesg if we get it wrong. So I don't think a in_irq
warning will add any value. Aside: hard/softirq isn't the only special
context lockdep checks for, it also checks for memory allocations,
e.g. if you hold a lock while calling kmalloc and your shrinker needs
the same locks it'll scream. That's why we have all the GFP_NORETRY
stuff when allocating memory and the trylock in the shrinker.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 17/24] drm/i915: kill dev_priv->rps.lock
  2013-06-12 11:37 ` [PATCH 17/24] drm/i915: kill dev_priv->rps.lock Daniel Vetter
@ 2013-06-28  3:35   ` Ben Widawsky
  2013-06-28  3:35   ` Ben Widawsky
  1 sibling, 0 replies; 86+ messages in thread
From: Ben Widawsky @ 2013-06-28  3:35 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 01:37:19PM +0200, Daniel Vetter wrote:
> Now that the rps interrupt locking isn't clearly separated (at elast
> conceptually) from all the other interrupt locking having a different
> lock stopped making sense. With this we can (again) unifiy the
> ringbuffer irq refcounts without causing a massive confusion, but
> that's for the next patch.

I think the original reason for the RPS lock still makes sense, so I'd
say your assertion should be that it's not worth the extra complexity,
which I can agree with. (The original use of the rps_lock was just for
the rps workqueue, it expanded a bunch since then).

> 
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_dma.c         |  1 -
>  drivers/gpu/drm/i915/i915_drv.h         |  8 ++++----
>  drivers/gpu/drm/i915/i915_irq.c         | 12 ++++++------
>  drivers/gpu/drm/i915/intel_pm.c         | 16 ++++++++--------
>  drivers/gpu/drm/i915/intel_ringbuffer.c |  8 ++++----
>  drivers/gpu/drm/i915/intel_ringbuffer.h |  2 +-
>  6 files changed, 23 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index b913b3d..14c3e9c 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1612,7 +1612,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>  
>  	spin_lock_init(&dev_priv->irq_lock);
>  	spin_lock_init(&dev_priv->gpu_error.lock);
> -	spin_lock_init(&dev_priv->rps.lock);
>  	spin_lock_init(&dev_priv->backlight.lock);
>  	mutex_init(&dev_priv->dpio_lock);
>  
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 07954b2..42d1363 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -691,12 +691,12 @@ struct i915_suspend_saved_registers {
>  };
>  
>  struct intel_gen6_power_mgmt {
> +	/* work and pm_iir are protected by dev_priv->irq_lock */
>  	struct work_struct work;
> -	struct delayed_work vlv_work;
>  	u32 pm_iir;
> -	/* lock - irqsave spinlock that protectects the work_struct and
> -	 * pm_iir. */
> -	spinlock_t lock;
> +
> +	/* On vlv we need to manually drop to Vmin with a delayed work. */
> +	struct delayed_work vlv_work;
A bit unrelated, but meh.
>  
>  	/* The below variables an all the rps hw state are protected by
>  	 * dev->struct mutext. */
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 752b98d..cd7135d 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -696,13 +696,13 @@ static void gen6_pm_rps_work(struct work_struct *work)
>  	u32 pm_iir, pm_imr;
>  	u8 new_delay;
>  
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	pm_iir = dev_priv->rps.pm_iir;
>  	dev_priv->rps.pm_iir = 0;
>  	pm_imr = I915_READ(GEN6_PMIMR);
>  	/* Make sure not to corrupt PMIMR state used by ringbuffer code */
>  	I915_WRITE(GEN6_PMIMR, pm_imr & ~GEN6_PM_RPS_EVENTS);
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  
>  	if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0)
>  		return;
> @@ -856,11 +856,11 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv,
>  	 * The mask bit in IMR is cleared by dev_priv->rps.work.
>  	 */
>  
> -	spin_lock(&dev_priv->rps.lock);
> +	spin_lock(&dev_priv->irq_lock);
>  	dev_priv->rps.pm_iir |= pm_iir;
>  	I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
>  	POSTING_READ(GEN6_PMIMR);
> -	spin_unlock(&dev_priv->rps.lock);
> +	spin_unlock(&dev_priv->irq_lock);
>  
>  	queue_work(dev_priv->wq, &dev_priv->rps.work);
>  }
> @@ -933,12 +933,12 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
>  			       u32 pm_iir)
>  {
>  	if (pm_iir & GEN6_PM_RPS_EVENTS) {
> -		spin_lock(&dev_priv->rps.lock);
> +		spin_lock(&dev_priv->irq_lock);
>  		dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
>  		I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
>  		/* never want to mask useful interrupts. (also posting read) */
>  		WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
> -		spin_unlock(&dev_priv->rps.lock);
> +		spin_unlock(&dev_priv->irq_lock);
>  
>  		queue_work(dev_priv->wq, &dev_priv->rps.work);
>  	}
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index adc44e4..6a5cfb5 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3128,9 +3128,9 @@ static void gen6_disable_rps(struct drm_device *dev)
>  	 * register (PMIMR) to mask PM interrupts. The only risk is in leaving
>  	 * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
>  
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	dev_priv->rps.pm_iir = 0;
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  
>  	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
>  }
> @@ -3147,9 +3147,9 @@ static void valleyview_disable_rps(struct drm_device *dev)
>  	 * register (PMIMR) to mask PM interrupts. The only risk is in leaving
>  	 * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
>  
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	dev_priv->rps.pm_iir = 0;
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  
>  	I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
>  
> @@ -3314,13 +3314,13 @@ static void gen6_enable_rps(struct drm_device *dev)
>  
>  	/* requires MSI enabled */
>  	I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS);
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	/* FIXME: Our interrupt enabling sequence is bonghits.
>  	 * dev_priv->rps.pm_iir really should be 0 here. */
>  	dev_priv->rps.pm_iir = 0;
>  	I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
>  	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  	/* unmask all PM interrupts */
>  	I915_WRITE(GEN6_PMINTRMSK, 0);
>  
> @@ -3585,10 +3585,10 @@ static void valleyview_enable_rps(struct drm_device *dev)
>  
>  	/* requires MSI enabled */
>  	I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS);
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	WARN_ON(dev_priv->rps.pm_iir != 0);
>  	I915_WRITE(GEN6_PMIMR, 0);
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  	/* enable all PM interrupts */
>  	I915_WRITE(GEN6_PMINTRMSK, 0);
>  
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 1ef081c..a7c9934 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1053,14 +1053,14 @@ hsw_vebox_get_irq(struct intel_ring_buffer *ring)
>  	if (!dev->irq_enabled)
>  		return false;
>  
> -	spin_lock_irqsave(&dev_priv->rps.lock, flags);
> +	spin_lock_irqsave(&dev_priv->irq_lock, flags);
>  	if (ring->irq_refcount.pm++ == 0) {
>  		u32 pm_imr = I915_READ(GEN6_PMIMR);
>  		I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
>  		I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
>  		POSTING_READ(GEN6_PMIMR);
>  	}
> -	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
> +	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
>  
>  	return true;
>  }
> @@ -1075,14 +1075,14 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring)
>  	if (!dev->irq_enabled)
>  		return;
>  
> -	spin_lock_irqsave(&dev_priv->rps.lock, flags);
> +	spin_lock_irqsave(&dev_priv->irq_lock, flags);
>  	if (--ring->irq_refcount.pm == 0) {
>  		u32 pm_imr = I915_READ(GEN6_PMIMR);
>  		I915_WRITE_IMR(ring, ~0);
>  		I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
>  		POSTING_READ(GEN6_PMIMR);
>  	}
> -	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
> +	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
>  }
>  
>  static int
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index efc403d..f960805 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -76,7 +76,7 @@ struct  intel_ring_buffer {
>  
>  	struct {
>  		u32	gt; /*  protected by dev_priv->irq_lock */
> -		u32	pm; /*  protected by dev_priv->rps.lock (sucks) */
> +		u32	pm; /*  protected by dev_priv->irq_lock */
>  	} irq_refcount;
>  	u32		irq_enable_mask;	/* bitmask to enable ring interrupt */
>  	u32		trace_irq_seqno;
> -- 
> 1.8.1.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 17/24] drm/i915: kill dev_priv->rps.lock
  2013-06-12 11:37 ` [PATCH 17/24] drm/i915: kill dev_priv->rps.lock Daniel Vetter
  2013-06-28  3:35   ` Ben Widawsky
@ 2013-06-28  3:35   ` Ben Widawsky
  1 sibling, 0 replies; 86+ messages in thread
From: Ben Widawsky @ 2013-06-28  3:35 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 01:37:19PM +0200, Daniel Vetter wrote:
> Now that the rps interrupt locking isn't clearly separated (at elast
> conceptually) from all the other interrupt locking having a different
> lock stopped making sense. With this we can (again) unifiy the
> ringbuffer irq refcounts without causing a massive confusion, but
> that's for the next patch.
> 
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Patches 14-17 are:
Reviewed-by: Ben Widawsky <ben@bwidawsk.net>

> ---
>  drivers/gpu/drm/i915/i915_dma.c         |  1 -
>  drivers/gpu/drm/i915/i915_drv.h         |  8 ++++----
>  drivers/gpu/drm/i915/i915_irq.c         | 12 ++++++------
>  drivers/gpu/drm/i915/intel_pm.c         | 16 ++++++++--------
>  drivers/gpu/drm/i915/intel_ringbuffer.c |  8 ++++----
>  drivers/gpu/drm/i915/intel_ringbuffer.h |  2 +-
>  6 files changed, 23 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index b913b3d..14c3e9c 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1612,7 +1612,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>  
>  	spin_lock_init(&dev_priv->irq_lock);
>  	spin_lock_init(&dev_priv->gpu_error.lock);
> -	spin_lock_init(&dev_priv->rps.lock);
>  	spin_lock_init(&dev_priv->backlight.lock);
>  	mutex_init(&dev_priv->dpio_lock);
>  
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 07954b2..42d1363 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -691,12 +691,12 @@ struct i915_suspend_saved_registers {
>  };
>  
>  struct intel_gen6_power_mgmt {
> +	/* work and pm_iir are protected by dev_priv->irq_lock */
>  	struct work_struct work;
> -	struct delayed_work vlv_work;
>  	u32 pm_iir;
> -	/* lock - irqsave spinlock that protectects the work_struct and
> -	 * pm_iir. */
> -	spinlock_t lock;
> +
> +	/* On vlv we need to manually drop to Vmin with a delayed work. */
> +	struct delayed_work vlv_work;
>  
>  	/* The below variables an all the rps hw state are protected by
>  	 * dev->struct mutext. */
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 752b98d..cd7135d 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -696,13 +696,13 @@ static void gen6_pm_rps_work(struct work_struct *work)
>  	u32 pm_iir, pm_imr;
>  	u8 new_delay;
>  
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	pm_iir = dev_priv->rps.pm_iir;
>  	dev_priv->rps.pm_iir = 0;
>  	pm_imr = I915_READ(GEN6_PMIMR);
>  	/* Make sure not to corrupt PMIMR state used by ringbuffer code */
>  	I915_WRITE(GEN6_PMIMR, pm_imr & ~GEN6_PM_RPS_EVENTS);
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  
>  	if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0)
>  		return;
> @@ -856,11 +856,11 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv,
>  	 * The mask bit in IMR is cleared by dev_priv->rps.work.
>  	 */
>  
> -	spin_lock(&dev_priv->rps.lock);
> +	spin_lock(&dev_priv->irq_lock);
>  	dev_priv->rps.pm_iir |= pm_iir;
>  	I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
>  	POSTING_READ(GEN6_PMIMR);
> -	spin_unlock(&dev_priv->rps.lock);
> +	spin_unlock(&dev_priv->irq_lock);
>  
>  	queue_work(dev_priv->wq, &dev_priv->rps.work);
>  }
> @@ -933,12 +933,12 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
>  			       u32 pm_iir)
>  {
>  	if (pm_iir & GEN6_PM_RPS_EVENTS) {
> -		spin_lock(&dev_priv->rps.lock);
> +		spin_lock(&dev_priv->irq_lock);
>  		dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
>  		I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
>  		/* never want to mask useful interrupts. (also posting read) */
>  		WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
> -		spin_unlock(&dev_priv->rps.lock);
> +		spin_unlock(&dev_priv->irq_lock);
>  
>  		queue_work(dev_priv->wq, &dev_priv->rps.work);
>  	}
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index adc44e4..6a5cfb5 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3128,9 +3128,9 @@ static void gen6_disable_rps(struct drm_device *dev)
>  	 * register (PMIMR) to mask PM interrupts. The only risk is in leaving
>  	 * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
>  
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	dev_priv->rps.pm_iir = 0;
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  
>  	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
>  }
> @@ -3147,9 +3147,9 @@ static void valleyview_disable_rps(struct drm_device *dev)
>  	 * register (PMIMR) to mask PM interrupts. The only risk is in leaving
>  	 * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
>  
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	dev_priv->rps.pm_iir = 0;
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  
>  	I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
>  
> @@ -3314,13 +3314,13 @@ static void gen6_enable_rps(struct drm_device *dev)
>  
>  	/* requires MSI enabled */
>  	I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS);
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	/* FIXME: Our interrupt enabling sequence is bonghits.
>  	 * dev_priv->rps.pm_iir really should be 0 here. */
>  	dev_priv->rps.pm_iir = 0;
>  	I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
>  	I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  	/* unmask all PM interrupts */
>  	I915_WRITE(GEN6_PMINTRMSK, 0);
>  
> @@ -3585,10 +3585,10 @@ static void valleyview_enable_rps(struct drm_device *dev)
>  
>  	/* requires MSI enabled */
>  	I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS);
> -	spin_lock_irq(&dev_priv->rps.lock);
> +	spin_lock_irq(&dev_priv->irq_lock);
>  	WARN_ON(dev_priv->rps.pm_iir != 0);
>  	I915_WRITE(GEN6_PMIMR, 0);
> -	spin_unlock_irq(&dev_priv->rps.lock);
> +	spin_unlock_irq(&dev_priv->irq_lock);
>  	/* enable all PM interrupts */
>  	I915_WRITE(GEN6_PMINTRMSK, 0);
>  
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 1ef081c..a7c9934 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1053,14 +1053,14 @@ hsw_vebox_get_irq(struct intel_ring_buffer *ring)
>  	if (!dev->irq_enabled)
>  		return false;
>  
> -	spin_lock_irqsave(&dev_priv->rps.lock, flags);
> +	spin_lock_irqsave(&dev_priv->irq_lock, flags);
>  	if (ring->irq_refcount.pm++ == 0) {
>  		u32 pm_imr = I915_READ(GEN6_PMIMR);
>  		I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
>  		I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
>  		POSTING_READ(GEN6_PMIMR);
>  	}
> -	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
> +	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
>  
>  	return true;
>  }
> @@ -1075,14 +1075,14 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring)
>  	if (!dev->irq_enabled)
>  		return;
>  
> -	spin_lock_irqsave(&dev_priv->rps.lock, flags);
> +	spin_lock_irqsave(&dev_priv->irq_lock, flags);
>  	if (--ring->irq_refcount.pm == 0) {
>  		u32 pm_imr = I915_READ(GEN6_PMIMR);
>  		I915_WRITE_IMR(ring, ~0);
>  		I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
>  		POSTING_READ(GEN6_PMIMR);
>  	}
> -	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
> +	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
>  }
>  
>  static int
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index efc403d..f960805 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -76,7 +76,7 @@ struct  intel_ring_buffer {
>  
>  	struct {
>  		u32	gt; /*  protected by dev_priv->irq_lock */
> -		u32	pm; /*  protected by dev_priv->rps.lock (sucks) */
> +		u32	pm; /*  protected by dev_priv->irq_lock */
>  	} irq_refcount;
>  	u32		irq_enable_mask;	/* bitmask to enable ring interrupt */
>  	u32		trace_irq_seqno;
> -- 
> 1.8.1.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH] drm/i915: irq handlers don't need interrupt-safe spinlocks
  2013-06-27 22:40       ` Daniel Vetter
@ 2013-06-28 16:57         ` Paulo Zanoni
  0 siblings, 0 replies; 86+ messages in thread
From: Paulo Zanoni @ 2013-06-28 16:57 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

2013/6/27 Daniel Vetter <daniel.vetter@ffwll.ch>:
> On Thu, Jun 27, 2013 at 11:14 PM, Paulo Zanoni <przanoni@gmail.com> wrote:
>> 2013/6/25 Daniel Vetter <daniel.vetter@ffwll.ch>:
>>> Since we only have one interrupt handler and interrupt handlers are
>>> non-reentrant.
>>>
>>> To drive the point really home give them all an _irq_handler suffix.
>>
>> Could we also add WARN(!in_irq()) or something equivalent for better
>> protection? Big backtraces are a nice way to discover we did something
>> wrong.
>
> Lockdep checks hard/soft irq context constraints and will scream
> horribly into dmesg if we get it wrong. So I don't think a in_irq
> warning will add any value. Aside: hard/softirq isn't the only special
> context lockdep checks for, it also checks for memory allocations,
> e.g. if you hold a lock while calling kmalloc and your shrinker needs
> the same locks it'll scream. That's why we have all the GFP_NORETRY
> stuff when allocating memory and the trylock in the shrinker.

Ok then. Looks like I forgot the stamp: Reviewed-by: Paulo Zanoni
<paulo.r.zanoni@intel.com>

> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 20/24] drm/i915: kill bogus GTIIR clearing in vlv_preinstall hook
  2013-06-12 11:37 ` [PATCH 20/24] drm/i915: kill bogus GTIIR clearing in vlv_preinstall hook Daniel Vetter
@ 2013-06-28 17:01   ` Ben Widawsky
  2013-07-04 20:56     ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Ben Widawsky @ 2013-06-28 17:01 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 01:37:22PM +0200, Daniel Vetter wrote:
> Preinstall disables interrupts, we clear the status register in the
> postinstall hook before we actually enable interrupt sources.
> 
> Also add a comment for the curios ring IMR masking, it doesn't
> seem to be required on any other platform.
> 
> We seem to have some room for common gt_preinstall/postinstall hooks.
> 
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 293ee68..b680e1c 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2546,13 +2546,12 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
>  
>  	/* VLV magic */
>  	I915_WRITE(VLV_IMR, 0);
> +	/* Do we really need to clear ring masks for vlv? */
>  	I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
>  	I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0);
>  	I915_WRITE(RING_IMR(BLT_RING_BASE), 0);

I actually like this for all GENs with rings as a documentation kind of
thing.

>  
>  	/* and GT */
> -	I915_WRITE(GTIIR, I915_READ(GTIIR));
> -	I915_WRITE(GTIIR, I915_READ(GTIIR));
>  	I915_WRITE(GTIMR, 0xffffffff);
>  	I915_WRITE(GTIER, 0x0);
>  	POSTING_READ(GTIER);

The ordering was wrong here anyway. I think to have the desired effect
it should have been
1. mask
2. disable
3. posting read
4. clear
5. posting read
6. clear // potential pending irq

But one thing this changes is the double clear, which I feel might be
necessary if it is meant to clear the pending interrupt as I would
guess. We only seem to do one in postinstall. If this change was
intentional, I think we should get Jesse to explain the origin of the
original double clear.

-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 18/24] drm/i915: unify ring irq refcounts (again)
  2013-06-12 11:37 ` [PATCH 18/24] drm/i915: unify ring irq refcounts (again) Daniel Vetter
@ 2013-06-28 17:24   ` Ben Widawsky
  2013-07-04 20:52     ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Ben Widawsky @ 2013-06-28 17:24 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 01:37:20PM +0200, Daniel Vetter wrote:
> With the simplified locking there's no reason any more to keep the
> refcounts seperate.

I guess my nitpick from previous patch is echoed here. The reason still
exists, the benefit just doesn't outweigh the complexity, and I think
we'd want separate enable_masks for pm/gt to make it worthwhile to use
separate refcounts.

Anyway, can you add a comment in the code about what irq_refcount does.
with that, it's
Reviewed-by: Ben Widawsky <ben@bwidawsk.net>

> 
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/intel_ringbuffer.c | 20 ++++++++++----------
>  drivers/gpu/drm/i915/intel_ringbuffer.h |  5 +----
>  2 files changed, 11 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index a7c9934..b75e9d0 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -819,7 +819,7 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring)
>  		return false;
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (ring->irq_refcount.gt++ == 0) {
> +	if (ring->irq_refcount++ == 0) {
>  		dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
>  		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
>  		POSTING_READ(GTIMR);
> @@ -837,7 +837,7 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring)
>  	unsigned long flags;
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (--ring->irq_refcount.gt == 0) {
> +	if (--ring->irq_refcount == 0) {
>  		dev_priv->gt_irq_mask |= ring->irq_enable_mask;
>  		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
>  		POSTING_READ(GTIMR);
> @@ -856,7 +856,7 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring)
>  		return false;
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (ring->irq_refcount.gt++ == 0) {
> +	if (ring->irq_refcount++ == 0) {
>  		dev_priv->irq_mask &= ~ring->irq_enable_mask;
>  		I915_WRITE(IMR, dev_priv->irq_mask);
>  		POSTING_READ(IMR);
> @@ -874,7 +874,7 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring)
>  	unsigned long flags;
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (--ring->irq_refcount.gt == 0) {
> +	if (--ring->irq_refcount == 0) {
>  		dev_priv->irq_mask |= ring->irq_enable_mask;
>  		I915_WRITE(IMR, dev_priv->irq_mask);
>  		POSTING_READ(IMR);
> @@ -893,7 +893,7 @@ i8xx_ring_get_irq(struct intel_ring_buffer *ring)
>  		return false;
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (ring->irq_refcount.gt++ == 0) {
> +	if (ring->irq_refcount++ == 0) {
>  		dev_priv->irq_mask &= ~ring->irq_enable_mask;
>  		I915_WRITE16(IMR, dev_priv->irq_mask);
>  		POSTING_READ16(IMR);
> @@ -911,7 +911,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring)
>  	unsigned long flags;
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (--ring->irq_refcount.gt == 0) {
> +	if (--ring->irq_refcount == 0) {
>  		dev_priv->irq_mask |= ring->irq_enable_mask;
>  		I915_WRITE16(IMR, dev_priv->irq_mask);
>  		POSTING_READ16(IMR);
> @@ -1004,7 +1004,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
>  	gen6_gt_force_wake_get(dev_priv);
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (ring->irq_refcount.gt++ == 0) {
> +	if (ring->irq_refcount++ == 0) {
>  		if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
>  			I915_WRITE_IMR(ring,
>  				       ~(ring->irq_enable_mask |
> @@ -1028,7 +1028,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
>  	unsigned long flags;
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (--ring->irq_refcount.gt == 0) {
> +	if (--ring->irq_refcount == 0) {
>  		if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
>  			I915_WRITE_IMR(ring,
>  				       ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
> @@ -1054,7 +1054,7 @@ hsw_vebox_get_irq(struct intel_ring_buffer *ring)
>  		return false;
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (ring->irq_refcount.pm++ == 0) {
> +	if (ring->irq_refcount++ == 0) {
>  		u32 pm_imr = I915_READ(GEN6_PMIMR);
>  		I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
>  		I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
> @@ -1076,7 +1076,7 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring)
>  		return;
>  
>  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> -	if (--ring->irq_refcount.pm == 0) {
> +	if (--ring->irq_refcount == 0) {
>  		u32 pm_imr = I915_READ(GEN6_PMIMR);
>  		I915_WRITE_IMR(ring, ~0);
>  		I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index f960805..26e304c 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -74,10 +74,7 @@ struct  intel_ring_buffer {
>  	 */
>  	u32		last_retired_head;
>  
> -	struct {
> -		u32	gt; /*  protected by dev_priv->irq_lock */
> -		u32	pm; /*  protected by dev_priv->irq_lock */
> -	} irq_refcount;
> +	unsigned irq_refcount;
>  	u32		irq_enable_mask;	/* bitmask to enable ring interrupt */
>  	u32		trace_irq_seqno;
>  	u32		sync_seqno[I915_NUM_RINGS-1];
> -- 
> 1.8.1.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT
  2013-06-12 18:32         ` Daniel Vetter
  2013-06-12 18:51           ` Ben Widawsky
@ 2013-06-28 17:25           ` Ben Widawsky
  1 sibling, 0 replies; 86+ messages in thread
From: Ben Widawsky @ 2013-06-28 17:25 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 08:32:44PM +0200, Daniel Vetter wrote:
> On Wed, Jun 12, 2013 at 8:19 PM, Ben Widawsky <ben@bwidawsk.net> wrote:
> > On Wed, Jun 12, 2013 at 07:18:38PM +0200, Daniel Vetter wrote:
> >> On Wed, Jun 12, 2013 at 10:13:41AM -0700, Ben Widawsky wrote:
> >> > On Wed, Jun 12, 2013 at 01:37:21PM +0200, Daniel Vetter wrote:
> >> > > The code to handle it is broken - there's simply no code to clear CS
> >> > > parser errors on gen5+. And behold, for all the other rings we also
> >> > > don't enable it!
> >> > >
> >> > > Leave the handling code itself in place just to be consistent with the
> >> > > existing mess though. And in case someone feels like fixing it all up.
> >> > >
> >> > > This has been errornously enabled in
> >> > >
> >> > > commit 12638c57f31952127c734c26315e1348fa1334c2
> >> > > Author: Ben Widawsky <ben@bwidawsk.net>
> >> > > Date:   Tue May 28 19:22:31 2013 -0700
> >> > >
> >> > >     drm/i915: Enable vebox interrupts
> >> > >
> >> > > Cc: Damien Lespiau <damien.lespiau@intel.com>
> >> > > Cc: Ben Widawsky <ben@bwidawsk.net>
> >> > > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >> > >
> >> > Why not fix the problem instead of just disabling the interrupt? Then
> >> > the "existing mess" is justified. It really shouldn't be terribly
> >> > difficult to fix it.
> >>
> >> Haven't seen it proven useful, and I don't want to blow through time just
> >> for fun on it. Hangcheck seems to be able to deal with it just fine.
> >> -Daniel
> > I don't get it. Isn't it just clearing a bit in the handler, vs.
> > clearing the flag here?
> 
> On a quick Bspec read we'd need to set up per-ring error interrupt
> registers, put them to sensible value in them, wire up the interrupt
> handling for each ring since ilk+ and then also test it. I really
> don't see the point in doing that. The only upshot of all that work is
> that if there's an instruction error we'd get an interrupt instead of
> waiting for the hangcheck to kick in.

Hmm. I still think you're overthinking this. I don't think it requires
so much work to get the parser interrupts, but I don't insist.

Reviewed-by: Ben Widawsky <ben@bwidawsk.net>

> 
> If you insist I can follow-up with a patch to just rip out the
> bare-bones handler we have now. Everything else really feels like
> wasted effort to me.
> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 21/24] drm/i915: unify PM interrupt preinstall sequence
  2013-06-12 11:37 ` [PATCH 21/24] drm/i915: unify PM interrupt preinstall sequence Daniel Vetter
@ 2013-06-28 17:26   ` Ben Widawsky
  2013-07-04 21:03     ` Daniel Vetter
  0 siblings, 1 reply; 86+ messages in thread
From: Ben Widawsky @ 2013-06-28 17:26 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

On Wed, Jun 12, 2013 at 01:37:23PM +0200, Daniel Vetter wrote:
> Since the addition of VECS we have a slightly different enable
> sequence for PM interrupts on ivb/hsw vs snb and vlv. Usually that
> will end up in hard to track down surprises.
> 
> Hence unifiy things and since we have copies of this code in 3 places
> now, extract it into its own little helper.
> 
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++++-----------------------
>  1 file changed, 17 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index b680e1c..954d8f8 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2486,17 +2486,9 @@ static void ibx_irq_preinstall(struct drm_device *dev)
>  	POSTING_READ(SDEIER);
>  }
>  
> -/* drm_dma.h hooks
> -*/
> -static void ironlake_irq_preinstall(struct drm_device *dev)
> +static void gen5_gt_irq_preinstall(struct drm_device *dev)
>  {
> -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> -
> -	atomic_set(&dev_priv->irq_received, 0);
> -
> -	I915_WRITE(HWSTAM, 0xeffe);
> -
> -	/* XXX hotplug from PCH */
> +	struct drm_i915_private *dev_priv = dev->dev_private;
>  
>  	I915_WRITE(DEIMR, 0xffffffff);
>  	I915_WRITE(DEIER, 0x0);
> @@ -2506,6 +2498,19 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
>  	I915_WRITE(GTIMR, 0xffffffff);
>  	I915_WRITE(GTIER, 0x0);
>  	POSTING_READ(GTIER);
> +}
> +
> +/* drm_dma.h hooks
> +*/
> +static void ironlake_irq_preinstall(struct drm_device *dev)
> +{
> +	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> +
> +	atomic_set(&dev_priv->irq_received, 0);
> +
> +	I915_WRITE(HWSTAM, 0xeffe);
> +
> +	gen5_gt_irq_preinstall(dev);
>  
>  	ibx_irq_preinstall(dev);
>  }
> @@ -2524,15 +2529,7 @@ static void ivybridge_irq_preinstall(struct drm_device *dev)
>  	I915_WRITE(DEIER, 0x0);
>  	POSTING_READ(DEIER);
>  
> -	/* and GT */
> -	I915_WRITE(GTIMR, 0xffffffff);
> -	I915_WRITE(GTIER, 0x0);
> -	POSTING_READ(GTIER);
> -
> -	/* Power management */
> -	I915_WRITE(GEN6_PMIMR, 0xffffffff);
> -	I915_WRITE(GEN6_PMIER, 0x0);
> -	POSTING_READ(GEN6_PMIER);
> +	gen5_gt_irq_preinstall(dev);
>  
>  	ibx_irq_preinstall(dev);

I lost what happened to
> -     I915_WRITE(GEN6_PMIMR, 0xffffffff);
> -     I915_WRITE(GEN6_PMIER, 0x0);
> -     POSTING_READ(GEN6_PMIER);


>  }
> @@ -2551,10 +2548,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
>  	I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0);
>  	I915_WRITE(RING_IMR(BLT_RING_BASE), 0);
>  
> -	/* and GT */
> -	I915_WRITE(GTIMR, 0xffffffff);
> -	I915_WRITE(GTIER, 0x0);
> -	POSTING_READ(GTIER);
> +	gen5_gt_irq_preinstall(dev);
>  
>  	I915_WRITE(DPINVGTT, 0xff);
>  
> -- 
> 1.8.1.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable
  2013-06-27 15:52             ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
                                 ` (4 preceding siblings ...)
  2013-06-27 15:52               ` [PATCH 6/6] drm/i915: fix hpd interrupt register locking Daniel Vetter
@ 2013-07-04 19:22               ` Daniel Vetter
  5 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-07-04 19:22 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

On Thu, Jun 27, 2013 at 05:52:10PM +0200, Daniel Vetter wrote:
> Just to keep the paranoia equal also sprinkle locking asserts over the
> pipestat interrupt enable/disable functions.
> 
> Again this results in false positives in the interrupt setup. Add
> bogo-locking for these and a big comment explaining why it's there and
> that it's indeed unnecessary.
> 
> v2: Fix up the spelling fail Paulo spotted in comments.
> 
> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Oops, somehow I've missed this patch here. It's now merged into dinq, too.
-Daniel

> ---
>  drivers/gpu/drm/i915/i915_irq.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 465588f..e7c879b 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -322,6 +322,8 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
>  	u32 reg = PIPESTAT(pipe);
>  	u32 pipestat = I915_READ(reg) & 0x7fff0000;
>  
> +	assert_spin_locked(&dev_priv->irq_lock);
> +
>  	if ((pipestat & mask) == mask)
>  		return;
>  
> @@ -337,6 +339,8 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
>  	u32 reg = PIPESTAT(pipe);
>  	u32 pipestat = I915_READ(reg) & 0x7fff0000;
>  
> +	assert_spin_locked(&dev_priv->irq_lock);
> +
>  	if ((pipestat & mask) == 0)
>  		return;
>  
> @@ -2826,6 +2830,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
>  	u32 gt_irqs;
>  	u32 enable_mask;
>  	u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
> +	unsigned long irqflags;
>  
>  	enable_mask = I915_DISPLAY_PORT_INTERRUPT;
>  	enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
> @@ -2851,9 +2856,13 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
>  	I915_WRITE(PIPESTAT(1), 0xffff);
>  	POSTING_READ(VLV_IER);
>  
> +	/* Interrupt setup is already guaranteed to be single-threaded, this is
> +	 * just to make the assert_spin_locked check happy. */
> +	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>  	i915_enable_pipestat(dev_priv, 0, pipestat_enable);
>  	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
>  	i915_enable_pipestat(dev_priv, 1, pipestat_enable);
> +	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
>  
>  	I915_WRITE(VLV_IIR, 0xffffffff);
>  	I915_WRITE(VLV_IIR, 0xffffffff);
> @@ -3335,6 +3344,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
>  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
>  	u32 enable_mask;
>  	u32 error_mask;
> +	unsigned long irqflags;
>  
>  	/* Unmask the interrupts that we always want on. */
>  	dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
> @@ -3353,7 +3363,11 @@ static int i965_irq_postinstall(struct drm_device *dev)
>  	if (IS_G4X(dev))
>  		enable_mask |= I915_BSD_USER_INTERRUPT;
>  
> +	/* Interrupt setup is already guaranteed to be single-threaded, this is
> +	 * just to make the assert_spin_locked check happy. */
> +	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>  	i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
> +	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
>  
>  	/*
>  	 * Enable some error detection, note the instruction error mask
> -- 
> 1.8.1.4
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 10/24] drm/i915: remove SERR_INT clearing in the postinstall hook
  2013-06-27 19:34   ` Paulo Zanoni
@ 2013-07-04 19:49     ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-07-04 19:49 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Daniel Vetter, Intel Graphics Development

On Thu, Jun 27, 2013 at 04:34:25PM -0300, Paulo Zanoni wrote:
> 2013/6/12 Daniel Vetter <daniel.vetter@ffwll.ch>:
> > The preinstallhook is supposed to clear all interrupts. Doing it
> > again in the postinstall hook has the risk that we're eating
> > an interrupt source from the handler. If that happens too often,
> > the kernel will disable our interrupt handler.
> 
> We do this with other registers too, why not remove those bits too
> then? I mean, SERR_INT is just like one of the IIR interrupts, and we
> always clear the IIR registers on postinstall functions. Can you
> please explain a little bit more?

You're right, we do clear the interrupt sticky bit clearing always in the
postinstall hooks. I still think this is wrong, or at least a bit risky
since the interrupt handler could fire as soon as we enable the master
interrupt enable bit. And atm we do that too early.

I think the right sequence is

1. Mask/disable interrupts in IMR/IER registers
2. Posting read
3. Clear IIR register, twice with a posting read (there's a little queue
in the hw ...). ERR error registers (or HOTPLUG_STAT/PIPESTAT on vlv) only
need one clear iirc.
4. Enable interrupt handler (i.e. 1.-3. above would be in the postinstall
hook)
5. Write only IMR/IER registers in the postinstall hook since those aren't
touched the interrupt handler (at least in general)

There's currently one exception: SDEIER, since that's also touched in the
interrupt handler. I think we need to handle DEIER similarly.

Comments?

The above is way more than just a simple patch though, so I think material
for a different patch series. I'll drop this one here (since it's broken
really, it only kills the clearing in postinstall but doesn't add it to
preinstall).

Cheers, Daniel

> 
> 
> >
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/i915_irq.c | 2 --
> >  1 file changed, 2 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index c2b4b09..685ad84 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -2635,8 +2635,6 @@ static void ibx_irq_postinstall(struct drm_device *dev)
> >                        SDE_TRANSA_FIFO_UNDER | SDE_POISON;
> >         } else {
> >                 mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
> > -
> > -               I915_WRITE(SERR_INT, I915_READ(SERR_INT));
> >         }
> >
> >         I915_WRITE(SDEIIR, I915_READ(SDEIIR));
> > --
> > 1.8.1.4
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
> 
> -- 
> Paulo Zanoni

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 11/24] drm/i915: improve SERR_INT clearing for fifo underrun reporting
  2013-06-27 20:19   ` Paulo Zanoni
@ 2013-07-04 19:55     ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-07-04 19:55 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Daniel Vetter, Intel Graphics Development

On Thu, Jun 27, 2013 at 05:19:06PM -0300, Paulo Zanoni wrote:
> 2013/6/12 Daniel Vetter <daniel.vetter@ffwll.ch>:
> > The current code won't report any fifo underruns on cpt if just one
> > pipe has fifo underrun reporting disabled. We can't enable the
> > interrupts, but we can still check the per-transcoder bits and so
> > report the underrun delayed if:
> > - We always clear the transcoder's bit (and none of the other bits)
> >   when enabling.
> > - We check the transcoder's bit after disabling (to avoid racing with
> >   the interrupt handler).
> 
> I guess you'll have to update this patch due to my bikeshed on IRC for
> patch 9. Anyway, comments below:
> 
> 
> >
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/i915_irq.c | 15 +++++++++++----
> >  drivers/gpu/drm/i915/i915_reg.h |  1 +
> >  2 files changed, 12 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index 685ad84..8627043 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -210,16 +210,23 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> >
> >         if (enable) {
> > +               I915_WRITE(SERR_INT,
> > +                          SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
> > +
> >                 if (!cpt_can_enable_serr_int(dev))
> >                         return;
> > -
> > -               I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN |
> > -                                    SERR_INT_TRANS_B_FIFO_UNDERRUN |
> > -                                    SERR_INT_TRANS_C_FIFO_UNDERRUN);
> >         }
> >
> >         ibx_display_interrupt_update(dev_priv, SDE_ERROR_CPT,
> >                                      enable ? SDE_ERROR_CPT : 0);
> > +
> > +       if (!enable) {
> > +               uint32_t tmp = I915_READ(SERR_INT);
> > +
> > +               if (tmp & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder))
> > +                       DRM_DEBUG_KMS("uncleared pch fifo underrun on pipe %i\n",
> > +                                     pch_transcoder);
> 
> Use %c and transcoder_name(pch_transcoder), otherwise you trigger
> people's OCDs again :)
> 
> Also, I think the logic in this patch is inverted.
> 
> Imagine everything is running correctly and the bits are all in the
> ideal state. Then we get an underrun report on transcoder A. We'll
> detect this inside cpt_serr_int_handler, call
> intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false), which
> will call cpt_set_fifo_underrun_reporting(dev, TRANSCODER_A, false).
> Then, inside your cpt_set_fifo_underrun_reporting, we'll disable
> SDE_ERROR_CPT, then read SERR_INT, see that the bit is 1 and print the
> DRM_DEBUG_KMS message you added. We'll return from
> cpt_set_fifo_underrun_reporting, then return from
> intel_set_pch_fifo_underrun_reporting, and then we'll print an error
> message again inside cpt_serr_int_handler. So we'll print 2 messages
> for a single underrun.
> 
> Instead of checking if the bit is 1 before disabling it, you should
> check if the bit is 1 before re-enabling it. The problem that you're
> trying to fix is that we don't report underruns while SDE_ERROR_CPT is
> disabled, so the solution is to ask "did we get any underruns while
> SDE_ERROR_CPT was disabled?", so inside the "if (enable)" case we need
> to check if the bit was 1, and on the "if (!enable)" case we need to
> clear the bit. Also, we should probably only print this "undetected
> pch fifo underrun" message if crtc->pch_fifo_underrun_disabled is
> false (otherwise we may report underruns on the same pipe multiple
> times).
> 
> I hope I'm not confused :)

Nope, the bug you've spotted is real afaics. But your proposed solution
isn't the best, since we want to report underruns latest when we disable
the pipe (even if underrun interrups are already disabled). If we only
check for the bit before re-enabling we could report false positives (in
case the disabling was indeed important and cause an expected underrun on
this pipe) and it's also already with a new configuration (if the change
is due to a modeset).

I have an idea how to fix this, I'll let you poke new holes into the
updated patch ;-)
-Daniel

> 
> 
> > +       }
> >  }
> >
> >  /**
> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > index b1fdca9..86e3987 100644
> > --- a/drivers/gpu/drm/i915/i915_reg.h
> > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > @@ -3880,6 +3880,7 @@
> >  #define  SERR_INT_TRANS_C_FIFO_UNDERRUN        (1<<6)
> >  #define  SERR_INT_TRANS_B_FIFO_UNDERRUN        (1<<3)
> >  #define  SERR_INT_TRANS_A_FIFO_UNDERRUN        (1<<0)
> > +#define  SERR_INT_TRANS_FIFO_UNDERRUN(pipe)    (1<< (pipe*3))
> >
> >  /* digital port hotplug */
> >  #define PCH_PORT_HOTPLUG        0xc4030                /* SHOTPLUG_CTL */
> > --
> > 1.8.1.4
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
> 
> -- 
> Paulo Zanoni

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns
  2013-06-27 20:45       ` Paulo Zanoni
@ 2013-07-04 20:41         ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-07-04 20:41 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Daniel Vetter, Intel Graphics Development

On Thu, Jun 27, 2013 at 05:45:29PM -0300, Paulo Zanoni wrote:
> 2013/6/12 Daniel Vetter <daniel.vetter@ffwll.ch>:
> > It's racy: There's no guarantee that we won't walk this code (due to a
> > pch fifo underrun interrupt) while someone is changing the pointers
> > around.
> 
> Can you please exemplify the "someone is changing the pointers around"
> case? I need to make sure I fully understand this.

While we do a modeset we change the encoder->crtc pointers around and
potentially zero them. Now we're lucky and we don't ever dereference that
pointer, so we can't OOPS on it (without locks or other tricks you can
read non-NULL when checking the pointer and then again NULL when
dereferencing). So here it's just that we could use different crtcs to
keep track of the fifo_underrun_reporting_disabled bit.

Nothing truely bad can happen, it just forces one to think for a bit too
long ;-)

btw there's a funny bug on module reloading where we seem to hit a fifo
underrun before the crtcs are properly set up. Which means we follow the
pipe_to_crtc pointers into NULL-land :( Different patch though.
-Daniel
> 
> 
> >
> > The only reason we do this is to use the righ crtc for the pch fifo
> > underrun accounting. But we never expose this to userspace, so
> > essentially no one really cares if we use the "wrong" crtc.
> >
> > So let's just rip it out.
> >
> > With this patch fifo underrun code will always use crtc A for tracking
> > underruns on the (only) pch transcoder on LPT.
> >
> > v2: Add a big comment explaining what's going on. Requested by Paulo.
> >
> > Cc: Paulo Zanoni <przanoni@gmail.com>
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++-------------------------
> >  1 file changed, 15 insertions(+), 25 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index bb26555..e80c610 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -193,13 +193,13 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
> >         POSTING_READ(SDEIMR);
> >  }
> >
> > -static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
> > +static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
> > +                                           enum transcoder pch_transcoder,
> >                                             bool enable)
> >  {
> > -       struct drm_device *dev = crtc->base.dev;
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > -       uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
> > -                                               SDE_TRANSB_FIFO_UNDER;
> > +       uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
> > +                      SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
> >
> >         ibx_display_interrupt_update(dev_priv, bit,
> >                                      enable ? bit : 0);
> > @@ -292,29 +292,19 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
> >                                            bool enable)
> >  {
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > -       enum pipe p;
> > -       struct drm_crtc *crtc;
> > -       struct intel_crtc *intel_crtc;
> > +       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
> > +       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> >         unsigned long flags;
> >         bool ret;
> >
> > -       if (HAS_PCH_LPT(dev)) {
> > -               crtc = NULL;
> > -               for_each_pipe(p) {
> > -                       struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p];
> > -                       if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) {
> > -                               crtc = c;
> > -                               break;
> > -                       }
> > -               }
> > -               if (!crtc) {
> > -                       DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n");
> > -                       return false;
> > -               }
> > -       } else {
> > -               crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
> > -       }
> > -       intel_crtc = to_intel_crtc(crtc);
> > +       /*
> > +        * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
> > +        * has has only one pch transcoder A that all pipes can use. To avoid
> 
> s/has has/has/
> 
> > +        * racy pch transcoder -> pipe lookups from interrupt code simply store
> > +        * the underrun statistics in crtc A. Since we never expose this
> > +        * anywhere nor use it outside of the fifo underrun code here using the
> 
> We do expose it to the user as an error message. On Haswell we call
> cpt_set_fifo_underrun_reporting, and you recently added a message
> there saying "uncleared pch fifo underrun on pipe %i". This is wrong
> since we'll always print "pipe A" on Haswell. If we reword the error
> message to say "on PCH transcoder A" then we'll be always correct.
> 
> 
> > +        * "wrong" crtc on LPT won't cause issues.
> > +        */
> >
> >         spin_lock_irqsave(&dev_priv->irq_lock, flags);
> >
> > @@ -326,7 +316,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
> >         intel_crtc->pch_fifo_underrun_disabled = !enable;
> >
> >         if (HAS_PCH_IBX(dev))
> > -               ibx_set_fifo_underrun_reporting(intel_crtc, enable);
> > +               ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
> >         else
> >                 cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
> >
> > --
> > 1.8.1.4
> >
> 
> 
> 
> -- 
> Paulo Zanoni

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 18/24] drm/i915: unify ring irq refcounts (again)
  2013-06-28 17:24   ` Ben Widawsky
@ 2013-07-04 20:52     ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-07-04 20:52 UTC (permalink / raw)
  To: Ben Widawsky; +Cc: Daniel Vetter, Intel Graphics Development

On Fri, Jun 28, 2013 at 10:24:32AM -0700, Ben Widawsky wrote:
> On Wed, Jun 12, 2013 at 01:37:20PM +0200, Daniel Vetter wrote:
> > With the simplified locking there's no reason any more to keep the
> > refcounts seperate.
> 
> I guess my nitpick from previous patch is echoed here. The reason still
> exists, the benefit just doesn't outweigh the complexity, and I think
> we'd want separate enable_masks for pm/gt to make it worthwhile to use
> separate refcounts.

Imo it's clear enough that ring->irq_refcount is a refcount for the ring
interrupt. I've added the lost comment how it is protected by the device
irq_lock again as compensation.
-Daniel

> 
> Anyway, can you add a comment in the code about what irq_refcount does.
> with that, it's
> Reviewed-by: Ben Widawsky <ben@bwidawsk.net>
> 
> > 
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/intel_ringbuffer.c | 20 ++++++++++----------
> >  drivers/gpu/drm/i915/intel_ringbuffer.h |  5 +----
> >  2 files changed, 11 insertions(+), 14 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> > index a7c9934..b75e9d0 100644
> > --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> > +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> > @@ -819,7 +819,7 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring)
> >  		return false;
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (ring->irq_refcount.gt++ == 0) {
> > +	if (ring->irq_refcount++ == 0) {
> >  		dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
> >  		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
> >  		POSTING_READ(GTIMR);
> > @@ -837,7 +837,7 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring)
> >  	unsigned long flags;
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (--ring->irq_refcount.gt == 0) {
> > +	if (--ring->irq_refcount == 0) {
> >  		dev_priv->gt_irq_mask |= ring->irq_enable_mask;
> >  		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
> >  		POSTING_READ(GTIMR);
> > @@ -856,7 +856,7 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring)
> >  		return false;
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (ring->irq_refcount.gt++ == 0) {
> > +	if (ring->irq_refcount++ == 0) {
> >  		dev_priv->irq_mask &= ~ring->irq_enable_mask;
> >  		I915_WRITE(IMR, dev_priv->irq_mask);
> >  		POSTING_READ(IMR);
> > @@ -874,7 +874,7 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring)
> >  	unsigned long flags;
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (--ring->irq_refcount.gt == 0) {
> > +	if (--ring->irq_refcount == 0) {
> >  		dev_priv->irq_mask |= ring->irq_enable_mask;
> >  		I915_WRITE(IMR, dev_priv->irq_mask);
> >  		POSTING_READ(IMR);
> > @@ -893,7 +893,7 @@ i8xx_ring_get_irq(struct intel_ring_buffer *ring)
> >  		return false;
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (ring->irq_refcount.gt++ == 0) {
> > +	if (ring->irq_refcount++ == 0) {
> >  		dev_priv->irq_mask &= ~ring->irq_enable_mask;
> >  		I915_WRITE16(IMR, dev_priv->irq_mask);
> >  		POSTING_READ16(IMR);
> > @@ -911,7 +911,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring)
> >  	unsigned long flags;
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (--ring->irq_refcount.gt == 0) {
> > +	if (--ring->irq_refcount == 0) {
> >  		dev_priv->irq_mask |= ring->irq_enable_mask;
> >  		I915_WRITE16(IMR, dev_priv->irq_mask);
> >  		POSTING_READ16(IMR);
> > @@ -1004,7 +1004,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
> >  	gen6_gt_force_wake_get(dev_priv);
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (ring->irq_refcount.gt++ == 0) {
> > +	if (ring->irq_refcount++ == 0) {
> >  		if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
> >  			I915_WRITE_IMR(ring,
> >  				       ~(ring->irq_enable_mask |
> > @@ -1028,7 +1028,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
> >  	unsigned long flags;
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (--ring->irq_refcount.gt == 0) {
> > +	if (--ring->irq_refcount == 0) {
> >  		if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
> >  			I915_WRITE_IMR(ring,
> >  				       ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
> > @@ -1054,7 +1054,7 @@ hsw_vebox_get_irq(struct intel_ring_buffer *ring)
> >  		return false;
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (ring->irq_refcount.pm++ == 0) {
> > +	if (ring->irq_refcount++ == 0) {
> >  		u32 pm_imr = I915_READ(GEN6_PMIMR);
> >  		I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
> >  		I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
> > @@ -1076,7 +1076,7 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring)
> >  		return;
> >  
> >  	spin_lock_irqsave(&dev_priv->irq_lock, flags);
> > -	if (--ring->irq_refcount.pm == 0) {
> > +	if (--ring->irq_refcount == 0) {
> >  		u32 pm_imr = I915_READ(GEN6_PMIMR);
> >  		I915_WRITE_IMR(ring, ~0);
> >  		I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
> > diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> > index f960805..26e304c 100644
> > --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> > +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> > @@ -74,10 +74,7 @@ struct  intel_ring_buffer {
> >  	 */
> >  	u32		last_retired_head;
> >  
> > -	struct {
> > -		u32	gt; /*  protected by dev_priv->irq_lock */
> > -		u32	pm; /*  protected by dev_priv->irq_lock */
> > -	} irq_refcount;
> > +	unsigned irq_refcount;
> >  	u32		irq_enable_mask;	/* bitmask to enable ring interrupt */
> >  	u32		trace_irq_seqno;
> >  	u32		sync_seqno[I915_NUM_RINGS-1];
> > -- 
> > 1.8.1.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Ben Widawsky, Intel Open Source Technology Center

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 20/24] drm/i915: kill bogus GTIIR clearing in vlv_preinstall hook
  2013-06-28 17:01   ` Ben Widawsky
@ 2013-07-04 20:56     ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-07-04 20:56 UTC (permalink / raw)
  To: Ben Widawsky; +Cc: Daniel Vetter, Intel Graphics Development

On Fri, Jun 28, 2013 at 10:01:12AM -0700, Ben Widawsky wrote:
> On Wed, Jun 12, 2013 at 01:37:22PM +0200, Daniel Vetter wrote:
> > Preinstall disables interrupts, we clear the status register in the
> > postinstall hook before we actually enable interrupt sources.
> > 
> > Also add a comment for the curios ring IMR masking, it doesn't
> > seem to be required on any other platform.
> > 
> > We seem to have some room for common gt_preinstall/postinstall hooks.
> > 
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/i915_irq.c | 3 +--
> >  1 file changed, 1 insertion(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index 293ee68..b680e1c 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -2546,13 +2546,12 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
> >  
> >  	/* VLV magic */
> >  	I915_WRITE(VLV_IMR, 0);
> > +	/* Do we really need to clear ring masks for vlv? */
> >  	I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
> >  	I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0);
> >  	I915_WRITE(RING_IMR(BLT_RING_BASE), 0);
> 
> I actually like this for all GENs with rings as a documentation kind of
> thing.
> 
> >  
> >  	/* and GT */
> > -	I915_WRITE(GTIIR, I915_READ(GTIIR));
> > -	I915_WRITE(GTIIR, I915_READ(GTIIR));
> >  	I915_WRITE(GTIMR, 0xffffffff);
> >  	I915_WRITE(GTIER, 0x0);
> >  	POSTING_READ(GTIER);
> 
> The ordering was wrong here anyway. I think to have the desired effect
> it should have been
> 1. mask
> 2. disable
> 3. posting read
> 4. clear
> 5. posting read
> 6. clear // potential pending irq
> 
> But one thing this changes is the double clear, which I feel might be
> necessary if it is meant to clear the pending interrupt as I would
> guess. We only seem to do one in postinstall. If this change was
> intentional, I think we should get Jesse to explain the origin of the
> original double clear.

Yeah, after some more thinking I agree with you. And in general we should
do all this in the preinstall hook for all IIR registers, since in the
postinstall hook the interupt handler could already be running. And we
shouldn't ever steal interrupt source bits from irq handler since doing
that too often will result in the interrupt getting disabled.

Another mail in this thread in reply to a question from Paulo has some
overall idea of how we should set up registers around interrupt enabling.

I'd appreciate your comments on that plan.

For now I'll drop this patch here and just keep it before calling the
generic function.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

* Re: [PATCH 21/24] drm/i915: unify PM interrupt preinstall sequence
  2013-06-28 17:26   ` Ben Widawsky
@ 2013-07-04 21:03     ` Daniel Vetter
  0 siblings, 0 replies; 86+ messages in thread
From: Daniel Vetter @ 2013-07-04 21:03 UTC (permalink / raw)
  To: Ben Widawsky; +Cc: Daniel Vetter, Intel Graphics Development

On Fri, Jun 28, 2013 at 10:26:37AM -0700, Ben Widawsky wrote:
> On Wed, Jun 12, 2013 at 01:37:23PM +0200, Daniel Vetter wrote:
> > Since the addition of VECS we have a slightly different enable
> > sequence for PM interrupts on ivb/hsw vs snb and vlv. Usually that
> > will end up in hard to track down surprises.
> > 
> > Hence unifiy things and since we have copies of this code in 3 places
> > now, extract it into its own little helper.
> > 
> > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++++-----------------------
> >  1 file changed, 17 insertions(+), 23 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index b680e1c..954d8f8 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -2486,17 +2486,9 @@ static void ibx_irq_preinstall(struct drm_device *dev)
> >  	POSTING_READ(SDEIER);
> >  }
> >  
> > -/* drm_dma.h hooks
> > -*/
> > -static void ironlake_irq_preinstall(struct drm_device *dev)
> > +static void gen5_gt_irq_preinstall(struct drm_device *dev)
> >  {
> > -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> > -
> > -	atomic_set(&dev_priv->irq_received, 0);
> > -
> > -	I915_WRITE(HWSTAM, 0xeffe);
> > -
> > -	/* XXX hotplug from PCH */
> > +	struct drm_i915_private *dev_priv = dev->dev_private;
> >  
> >  	I915_WRITE(DEIMR, 0xffffffff);
> >  	I915_WRITE(DEIER, 0x0);
> > @@ -2506,6 +2498,19 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
> >  	I915_WRITE(GTIMR, 0xffffffff);
> >  	I915_WRITE(GTIER, 0x0);
> >  	POSTING_READ(GTIER);
> > +}
> > +
> > +/* drm_dma.h hooks
> > +*/
> > +static void ironlake_irq_preinstall(struct drm_device *dev)
> > +{
> > +	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> > +
> > +	atomic_set(&dev_priv->irq_received, 0);
> > +
> > +	I915_WRITE(HWSTAM, 0xeffe);
> > +
> > +	gen5_gt_irq_preinstall(dev);
> >  
> >  	ibx_irq_preinstall(dev);
> >  }
> > @@ -2524,15 +2529,7 @@ static void ivybridge_irq_preinstall(struct drm_device *dev)
> >  	I915_WRITE(DEIER, 0x0);
> >  	POSTING_READ(DEIER);
> >  
> > -	/* and GT */
> > -	I915_WRITE(GTIMR, 0xffffffff);
> > -	I915_WRITE(GTIER, 0x0);
> > -	POSTING_READ(GTIER);
> > -
> > -	/* Power management */
> > -	I915_WRITE(GEN6_PMIMR, 0xffffffff);
> > -	I915_WRITE(GEN6_PMIER, 0x0);
> > -	POSTING_READ(GEN6_PMIER);
> > +	gen5_gt_irq_preinstall(dev);
> >  
> >  	ibx_irq_preinstall(dev);
> 
> I lost what happened to

Have been lost, thanks for spotting this.
-Daniel

> > -     I915_WRITE(GEN6_PMIMR, 0xffffffff);
> > -     I915_WRITE(GEN6_PMIER, 0x0);
> > -     POSTING_READ(GEN6_PMIER);
> 
> 
> >  }
> > @@ -2551,10 +2548,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
> >  	I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0);
> >  	I915_WRITE(RING_IMR(BLT_RING_BASE), 0);
> >  
> > -	/* and GT */
> > -	I915_WRITE(GTIMR, 0xffffffff);
> > -	I915_WRITE(GTIER, 0x0);
> > -	POSTING_READ(GTIER);
> > +	gen5_gt_irq_preinstall(dev);
> >  
> >  	I915_WRITE(DPINVGTT, 0xff);
> >  
> > -- 
> > 1.8.1.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Ben Widawsky, Intel Open Source Technology Center

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 86+ messages in thread

end of thread, other threads:[~2013-07-04 21:04 UTC | newest]

Thread overview: 86+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-12 11:37 [PATCH 00/24] irq locking review Daniel Vetter
2013-06-12 11:37 ` [PATCH 01/24] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
2013-06-25 12:26   ` [PATCH] " Daniel Vetter
2013-06-26 21:15     ` Paulo Zanoni
2013-06-27 10:37       ` Daniel Vetter
2013-06-12 11:37 ` [PATCH 02/24] drm/i915: close tiny race in the ilk pcu even interrupt setup Daniel Vetter
2013-06-26 21:20   ` Paulo Zanoni
2013-06-12 11:37 ` [PATCH 03/24] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
2013-06-26 21:44   ` Paulo Zanoni
2013-06-12 11:37 ` [PATCH 04/24] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
2013-06-12 14:22   ` Egbert Eich
2013-06-12 11:37 ` [PATCH 05/24] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler Daniel Vetter
     [not found]   ` <20920.34096.704203.67316@linux-qknr.site>
2013-06-12 15:00     ` Daniel Vetter
2013-06-12 11:37 ` [PATCH 06/24] drm/i915: fold the queue_work " Daniel Vetter
2013-06-12 14:29   ` Egbert Eich
2013-06-12 11:37 ` [PATCH 07/24] drm/i915: fold the no-irq check " Daniel Vetter
2013-06-12 14:33   ` Egbert Eich
2013-06-26 22:35     ` Paulo Zanoni
2013-06-27 10:39       ` Daniel Vetter
2013-06-27 11:44       ` [PATCH 1/8] drm/i915: fix locking around ironlake_enable|disable_display_irq Daniel Vetter
2013-06-27 11:44         ` [PATCH 2/8] drm/i915: close tiny race in the ilk pcu even interrupt setup Daniel Vetter
2013-06-27 11:45         ` [PATCH 3/8] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
2013-06-27 11:45         ` [PATCH 4/8] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
2013-06-27 11:45         ` [PATCH 5/8] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler Daniel Vetter
2013-06-27 11:45         ` [PATCH 6/8] drm/i915: fold the queue_work " Daniel Vetter
2013-06-27 12:13           ` Chris Wilson
2013-06-27 11:45         ` [PATCH 7/8] drm/i915: fold the no-irq check " Daniel Vetter
2013-06-27 12:14           ` Chris Wilson
2013-06-27 11:45         ` [PATCH 8/8] drm/i915: fix hpd interrupt register locking Daniel Vetter
2013-06-27 14:41           ` Paulo Zanoni
2013-06-27 15:52             ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
2013-06-27 15:52               ` [PATCH 2/6] drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ Daniel Vetter
2013-06-27 15:52               ` [PATCH 3/6] drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler Daniel Vetter
2013-06-27 15:52               ` [PATCH 4/6] drm/i915: fold the queue_work " Daniel Vetter
2013-06-27 15:52               ` [PATCH 5/6] drm/i915: fold the no-irq check " Daniel Vetter
2013-06-27 15:52               ` [PATCH 6/6] drm/i915: fix hpd interrupt register locking Daniel Vetter
2013-07-04 19:22               ` [PATCH 1/6] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Daniel Vetter
2013-06-27 17:44             ` [PATCH 8/8] drm/i915: fix hpd interrupt register locking Daniel Vetter
2013-06-12 11:37 ` [PATCH 08/24] " Daniel Vetter
2013-06-12 14:59   ` Egbert Eich
2013-06-12 15:10     ` Daniel Vetter
2013-06-12 11:37 ` [PATCH 09/24] drm/i915: extract ibx_display_interrupt_update Daniel Vetter
2013-06-25 12:27   ` [PATCH] " Daniel Vetter
2013-06-12 11:37 ` [PATCH 10/24] drm/i915: remove SERR_INT clearing in the postinstall hook Daniel Vetter
2013-06-27 19:34   ` Paulo Zanoni
2013-07-04 19:49     ` Daniel Vetter
2013-06-12 11:37 ` [PATCH 11/24] drm/i915: improve SERR_INT clearing for fifo underrun reporting Daniel Vetter
2013-06-27 20:19   ` Paulo Zanoni
2013-07-04 19:55     ` Daniel Vetter
2013-06-12 11:37 ` [PATCH 12/24] drm/i915: improve GEN7_ERR_INT " Daniel Vetter
2013-06-12 11:37 ` [PATCH 13/24] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns Daniel Vetter
2013-06-12 13:04   ` Paulo Zanoni
2013-06-12 14:46     ` [PATCH] " Daniel Vetter
2013-06-27 20:45       ` Paulo Zanoni
2013-07-04 20:41         ` Daniel Vetter
2013-06-12 11:37 ` [PATCH 14/24] drm/i915: irq handlers don't need interrupt-safe spinlocks Daniel Vetter
2013-06-25 12:27   ` [PATCH] " Daniel Vetter
2013-06-27 21:14     ` Paulo Zanoni
2013-06-27 22:40       ` Daniel Vetter
2013-06-28 16:57         ` Paulo Zanoni
2013-06-12 11:37 ` [PATCH 15/24] drm/i915: streamline hsw_pm_irq_handler Daniel Vetter
2013-06-25 12:28   ` [PATCH] " Daniel Vetter
2013-06-12 11:37 ` [PATCH 16/24] drm/i915: queue work outside spinlock in hsw_pm_irq_handler Daniel Vetter
2013-06-12 11:37 ` [PATCH 17/24] drm/i915: kill dev_priv->rps.lock Daniel Vetter
2013-06-28  3:35   ` Ben Widawsky
2013-06-28  3:35   ` Ben Widawsky
2013-06-12 11:37 ` [PATCH 18/24] drm/i915: unify ring irq refcounts (again) Daniel Vetter
2013-06-28 17:24   ` Ben Widawsky
2013-07-04 20:52     ` Daniel Vetter
2013-06-12 11:37 ` [PATCH 19/24] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT Daniel Vetter
2013-06-12 17:13   ` Ben Widawsky
2013-06-12 17:18     ` Daniel Vetter
2013-06-12 18:19       ` Ben Widawsky
2013-06-12 18:32         ` Daniel Vetter
2013-06-12 18:51           ` Ben Widawsky
2013-06-28 17:25           ` Ben Widawsky
2013-06-12 11:37 ` [PATCH 20/24] drm/i915: kill bogus GTIIR clearing in vlv_preinstall hook Daniel Vetter
2013-06-28 17:01   ` Ben Widawsky
2013-07-04 20:56     ` Daniel Vetter
2013-06-12 11:37 ` [PATCH 21/24] drm/i915: unify PM interrupt preinstall sequence Daniel Vetter
2013-06-28 17:26   ` Ben Widawsky
2013-07-04 21:03     ` Daniel Vetter
2013-06-12 11:37 ` [PATCH 22/24] drm/i915: unify GT/PM irq postinstall code Daniel Vetter
2013-06-12 11:37 ` [PATCH 23/24] drm/i915: extract rps interrupt enable/disable helpers Daniel Vetter
2013-06-12 11:37 ` [PATCH 24/24] drm/i915: simplify rps interrupt enabling/disabling sequence Daniel Vetter
2013-06-12 22:32   ` Ben Widawsky

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.