All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Enable PM Interrupts for BDW
@ 2014-04-14 17:11 deepak.s
  2014-04-14 17:11 ` [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler deepak.s
  2014-04-14 17:11 ` [PATCH 2/2] drm/i915: Enable PM Interrupts target via Display Interface deepak.s
  0 siblings, 2 replies; 12+ messages in thread
From: deepak.s @ 2014-04-14 17:11 UTC (permalink / raw)
  To: intel-gfx; +Cc: Deepak S

From: Deepak S <deepak.s@intel.com>

Added patch to enable PM Interrupts 

Ben Widawsky (1):
  drm/i915/bdw: Implement a basic PM interrupt handler

Deepak S (1):
  drm/i915: Enable PM Interrupts target via Display Interface.

 drivers/gpu/drm/i915/i915_irq.c  | 81 +++++++++++++++++++++++++++++++++++++---
 drivers/gpu/drm/i915/i915_reg.h  |  2 +
 drivers/gpu/drm/i915/intel_drv.h |  3 +-
 drivers/gpu/drm/i915/intel_pm.c  | 40 +++++++++++++++++++-
 4 files changed, 118 insertions(+), 8 deletions(-)

-- 
1.8.5.2

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

* [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler
  2014-04-14 17:11 [PATCH 0/2] Enable PM Interrupts for BDW deepak.s
@ 2014-04-14 17:11 ` deepak.s
  2014-04-14 19:55   ` Ville Syrjälä
  2014-04-14 17:11 ` [PATCH 2/2] drm/i915: Enable PM Interrupts target via Display Interface deepak.s
  1 sibling, 1 reply; 12+ messages in thread
From: deepak.s @ 2014-04-14 17:11 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ben Widawsky, Ben Widawsky

From: Ben Widawsky <benjamin.widawsky@intel.com>

Almost all of it is reusable from the existing code. The primary
difference is we need to do even less in the interrupt handler, since
interrupts are not shared in the same way.

The patch is mostly a copy-paste of the existing snb+ code, with updates
to the relevant parts requiring changes to the interrupt handling. As
such it /should/ be relatively trivial. It's highly likely that I missed
some places where I need a gen8 version of the PM interrupts, but it has
become invisible to me by now.

This patch could probably be split into adding the new functions,
followed by actually handling the interrupts. Since the code is
currently disabled (and broken) I think the patch stands better by
itself.

v2: Move the commit about not touching the ringbuffer interrupt to the
snb_* function where it belongs (Rodrigo)

v3: Rebased on Paulo's runtime PM changes

v4: Not well validated, but rebase on
commit 730488b2eddded4497f63f70867b1256cd9e117c
Author: Paulo Zanoni <paulo.r.zanoni@intel.com>
Date:   Fri Mar 7 20:12:32 2014 -0300

    drm/i915: kill dev_priv->pm.regsave

v5: Rebased on latest code base. (Deepak)

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

Conflicts:
	drivers/gpu/drm/i915/i915_irq.c
---
 drivers/gpu/drm/i915/i915_irq.c  | 81 +++++++++++++++++++++++++++++++++++++---
 drivers/gpu/drm/i915/i915_reg.h  |  1 +
 drivers/gpu/drm/i915/intel_drv.h |  3 +-
 drivers/gpu/drm/i915/intel_pm.c  | 38 ++++++++++++++++++-
 4 files changed, 115 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 7a4d3ae..96c459a 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -248,6 +248,50 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
 	return true;
 }
 
+/**
+  * bdw_update_pm_irq - update GT interrupt 2
+  * @dev_priv: driver private
+  * @interrupt_mask: mask of interrupt bits to update
+  * @enabled_irq_mask: mask of interrupt bits to enable
+  *
+  * Copied from the snb function, updated with relevant register offsets
+  */
+static void bdw_update_pm_irq(struct drm_i915_private *dev_priv,
+			      uint32_t interrupt_mask,
+			      uint32_t enabled_irq_mask)
+{
+	uint32_t new_val;
+
+	assert_spin_locked(&dev_priv->irq_lock);
+
+	if (dev_priv->pm.irqs_disabled) {
+		WARN(1, "IRQs disabled\n");
+		return;
+	}
+
+	new_val = dev_priv->pm_irq_mask;
+	new_val &= ~interrupt_mask;
+	new_val |= (~enabled_irq_mask & interrupt_mask);
+
+	if (new_val != dev_priv->pm_irq_mask) {
+		dev_priv->pm_irq_mask = new_val;
+		I915_WRITE(GEN8_GT_IMR(2), I915_READ(GEN8_GT_IMR(2)) |
+					   dev_priv->pm_irq_mask);
+		POSTING_READ(GEN8_GT_IMR(2));
+	}
+}
+
+void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
+{
+	bdw_update_pm_irq(dev_priv, mask, mask);
+}
+
+void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
+{
+	bdw_update_pm_irq(dev_priv, mask, 0);
+}
+
+
 static bool cpt_can_enable_serr_int(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1126,13 +1170,17 @@ static void gen6_pm_rps_work(struct work_struct *work)
 	spin_lock_irq(&dev_priv->irq_lock);
 	pm_iir = dev_priv->rps.pm_iir;
 	dev_priv->rps.pm_iir = 0;
-	/* Make sure not to corrupt PMIMR state used by ringbuffer code */
-	snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+	if (IS_BROADWELL(dev_priv->dev))
+		bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+	else {
+		/* Make sure not to corrupt PMIMR state used by ringbuffer */
+		snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+		/* Make sure we didn't queue anything we're not going to
+		 * process. */
+		WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
+	}
 	spin_unlock_irq(&dev_priv->irq_lock);
 
-	/* Make sure we didn't queue anything we're not going to process. */
-	WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
-
 	if ((pm_iir & dev_priv->pm_rps_events) == 0)
 		return;
 
@@ -1324,6 +1372,19 @@ static void snb_gt_irq_handler(struct drm_device *dev,
 		ivybridge_parity_error_irq_handler(dev, gt_iir);
 }
 
+static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
+{
+	if ((pm_iir & dev_priv->pm_rps_events) == 0)
+		return;
+
+	spin_lock(&dev_priv->irq_lock);
+	dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
+	bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
+	spin_unlock(&dev_priv->irq_lock);
+
+	queue_work(dev_priv->wq, &dev_priv->rps.work);
+}
+
 static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 				       struct drm_i915_private *dev_priv,
 				       u32 master_ctl)
@@ -1359,6 +1420,16 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
 	}
 
+	if (master_ctl & GEN8_GT_PM_IRQ) {
+		tmp = I915_READ(GEN8_GT_IIR(2));
+		if (tmp & dev_priv->pm_rps_events) {
+			ret = IRQ_HANDLED;
+			gen8_rps_irq_handler(dev_priv, tmp);
+			I915_WRITE(GEN8_GT_IIR(1), tmp & dev_priv->pm_rps_events);
+		} else
+			DRM_ERROR("The master control interrupt lied (PM)!\n");
+	}
+
 	if (master_ctl & GEN8_GT_VECS_IRQ) {
 		tmp = I915_READ(GEN8_GT_IIR(3));
 		if (tmp) {
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 8f84555..c2dd436 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -4193,6 +4193,7 @@ enum punit_power_well {
 #define  GEN8_DE_PIPE_A_IRQ		(1<<16)
 #define  GEN8_DE_PIPE_IRQ(pipe)		(1<<(16+pipe))
 #define  GEN8_GT_VECS_IRQ		(1<<6)
+#define  GEN8_GT_PM_IRQ			(1<<4)
 #define  GEN8_GT_VCS2_IRQ		(1<<3)
 #define  GEN8_GT_VCS1_IRQ		(1<<2)
 #define  GEN8_GT_BCS_IRQ		(1<<1)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c551472..68a078c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -650,10 +650,11 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
+void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
+void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
 void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
 
-
 /* intel_crt.c */
 void intel_crt_init(struct drm_device *dev);
 
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 75c1c76..27b64ab 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3210,6 +3210,25 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
 	trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
 }
 
+static void gen8_disable_rps_interrupts(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+	I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
+				   ~dev_priv->pm_rps_events);
+	/* 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. */
+
+	spin_lock_irq(&dev_priv->irq_lock);
+	dev_priv->rps.pm_iir = 0;
+	spin_unlock_irq(&dev_priv->irq_lock);
+
+	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
+}
+
 static void gen6_disable_rps_interrupts(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3236,7 +3255,10 @@ static void gen6_disable_rps(struct drm_device *dev)
 	I915_WRITE(GEN6_RC_CONTROL, 0);
 	I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
 
-	gen6_disable_rps_interrupts(dev);
+	if (IS_BROADWELL(dev))
+		gen8_disable_rps_interrupts(dev);
+	else
+		gen6_disable_rps_interrupts(dev);
 }
 
 static void valleyview_disable_rps(struct drm_device *dev)
@@ -3276,6 +3298,18 @@ int intel_enable_rc6(const struct drm_device *dev)
 	return INTEL_RC6_ENABLE;
 }
 
+static void gen8_enable_rps_interrupts(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	spin_lock_irq(&dev_priv->irq_lock);
+	WARN_ON(dev_priv->rps.pm_iir);
+	bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
+	spin_unlock_irq(&dev_priv->irq_lock);
+
+}
+
 static void gen6_enable_rps_interrupts(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3378,7 +3412,7 @@ static void gen8_enable_rps(struct drm_device *dev)
 
 	gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8);
 
-	gen6_enable_rps_interrupts(dev);
+	gen8_enable_rps_interrupts(dev);
 
 	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
-- 
1.8.5.2

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

* [PATCH 2/2] drm/i915: Enable PM Interrupts target via Display Interface.
  2014-04-14 17:11 [PATCH 0/2] Enable PM Interrupts for BDW deepak.s
  2014-04-14 17:11 ` [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler deepak.s
@ 2014-04-14 17:11 ` deepak.s
  2014-04-14 19:36   ` Ville Syrjälä
  1 sibling, 1 reply; 12+ messages in thread
From: deepak.s @ 2014-04-14 17:11 UTC (permalink / raw)
  To: intel-gfx; +Cc: Deepak S

From: Deepak S <deepak.s@intel.com>

In BDW, Apart from unmasking up/down threshold interrupts. we need
to umask bit 32 of PM_INTRMASK to route interrupts to target via Display
Interface.

Signed-off-by: Deepak S <deepak.s@intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h | 1 +
 drivers/gpu/drm/i915/intel_pm.c | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index c2dd436..8c7841b 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -5105,6 +5105,7 @@ enum punit_power_well {
 #define GEN6_RC6p_THRESHOLD			0xA0BC
 #define GEN6_RC6pp_THRESHOLD			0xA0C0
 #define GEN6_PMINTRMSK				0xA168
+#define GEN8_PMINTR_REDIRECT_TO_NON_DISP	0x7FFFFFFF
 
 #define GEN6_PMISR				0x44020
 #define GEN6_PMIMR				0x44024 /* rps_lock */
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 27b64ab..6b123cd 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3066,6 +3066,8 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
 	if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev))
 		mask |= GEN6_PM_RP_UP_EI_EXPIRED;
 
+	mask &= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
+
 	return ~mask;
 }
 
-- 
1.8.5.2

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

* Re: [PATCH 2/2] drm/i915: Enable PM Interrupts target via Display Interface.
  2014-04-14 17:11 ` [PATCH 2/2] drm/i915: Enable PM Interrupts target via Display Interface deepak.s
@ 2014-04-14 19:36   ` Ville Syrjälä
  2014-04-16 13:32     ` Ville Syrjälä
  0 siblings, 1 reply; 12+ messages in thread
From: Ville Syrjälä @ 2014-04-14 19:36 UTC (permalink / raw)
  To: deepak.s; +Cc: intel-gfx

On Mon, Apr 14, 2014 at 10:41:15PM +0530, deepak.s@intel.com wrote:
> From: Deepak S <deepak.s@intel.com>
> 
> In BDW, Apart from unmasking up/down threshold interrupts. we need
> to umask bit 32 of PM_INTRMASK to route interrupts to target via Display
> Interface.
> 
> Signed-off-by: Deepak S <deepak.s@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_reg.h | 1 +
>  drivers/gpu/drm/i915/intel_pm.c | 2 ++
>  2 files changed, 3 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index c2dd436..8c7841b 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -5105,6 +5105,7 @@ enum punit_power_well {
>  #define GEN6_RC6p_THRESHOLD			0xA0BC
>  #define GEN6_RC6pp_THRESHOLD			0xA0C0
>  #define GEN6_PMINTRMSK				0xA168
> +#define GEN8_PMINTR_REDIRECT_TO_NON_DISP	0x7FFFFFFF

Defining is as (1<<31) would make more sense to me.

>  
>  #define GEN6_PMISR				0x44020
>  #define GEN6_PMIMR				0x44024 /* rps_lock */
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 27b64ab..6b123cd 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3066,6 +3066,8 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
>  	if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev))
>  		mask |= GEN6_PM_RP_UP_EI_EXPIRED;
>  
> +	mask &= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
> +
>  	return ~mask;
>  }
>  
> -- 
> 1.8.5.2
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC

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

* Re: [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler
  2014-04-14 17:11 ` [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler deepak.s
@ 2014-04-14 19:55   ` Ville Syrjälä
  2014-04-16  2:43     ` Ben Widawsky
  0 siblings, 1 reply; 12+ messages in thread
From: Ville Syrjälä @ 2014-04-14 19:55 UTC (permalink / raw)
  To: deepak.s; +Cc: intel-gfx, Ben Widawsky, Ben Widawsky

On Mon, Apr 14, 2014 at 10:41:14PM +0530, deepak.s@intel.com wrote:
> From: Ben Widawsky <benjamin.widawsky@intel.com>
> 
> Almost all of it is reusable from the existing code. The primary
> difference is we need to do even less in the interrupt handler, since
> interrupts are not shared in the same way.
> 
> The patch is mostly a copy-paste of the existing snb+ code, with updates
> to the relevant parts requiring changes to the interrupt handling. As
> such it /should/ be relatively trivial. It's highly likely that I missed
> some places where I need a gen8 version of the PM interrupts, but it has
> become invisible to me by now.
> 
> This patch could probably be split into adding the new functions,
> followed by actually handling the interrupts. Since the code is
> currently disabled (and broken) I think the patch stands better by
> itself.
> 
> v2: Move the commit about not touching the ringbuffer interrupt to the
> snb_* function where it belongs (Rodrigo)
> 
> v3: Rebased on Paulo's runtime PM changes
> 
> v4: Not well validated, but rebase on
> commit 730488b2eddded4497f63f70867b1256cd9e117c
> Author: Paulo Zanoni <paulo.r.zanoni@intel.com>
> Date:   Fri Mar 7 20:12:32 2014 -0300
> 
>     drm/i915: kill dev_priv->pm.regsave
> 
> v5: Rebased on latest code base. (Deepak)
> 
> Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
> 
> Conflicts:
> 	drivers/gpu/drm/i915/i915_irq.c

IIRC Daniel doesn't like these conflict markers. So should be dropped.

> ---
>  drivers/gpu/drm/i915/i915_irq.c  | 81 +++++++++++++++++++++++++++++++++++++---
>  drivers/gpu/drm/i915/i915_reg.h  |  1 +
>  drivers/gpu/drm/i915/intel_drv.h |  3 +-
>  drivers/gpu/drm/i915/intel_pm.c  | 38 ++++++++++++++++++-
>  4 files changed, 115 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 7a4d3ae..96c459a 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -248,6 +248,50 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
>  	return true;
>  }
>  
> +/**
> +  * bdw_update_pm_irq - update GT interrupt 2
> +  * @dev_priv: driver private
> +  * @interrupt_mask: mask of interrupt bits to update
> +  * @enabled_irq_mask: mask of interrupt bits to enable
> +  *
> +  * Copied from the snb function, updated with relevant register offsets
> +  */
> +static void bdw_update_pm_irq(struct drm_i915_private *dev_priv,
> +			      uint32_t interrupt_mask,
> +			      uint32_t enabled_irq_mask)
> +{
> +	uint32_t new_val;
> +
> +	assert_spin_locked(&dev_priv->irq_lock);
> +
> +	if (dev_priv->pm.irqs_disabled) {
> +		WARN(1, "IRQs disabled\n");
> +		return;
> +	}
> +
> +	new_val = dev_priv->pm_irq_mask;
> +	new_val &= ~interrupt_mask;
> +	new_val |= (~enabled_irq_mask & interrupt_mask);
> +
> +	if (new_val != dev_priv->pm_irq_mask) {
> +		dev_priv->pm_irq_mask = new_val;
> +		I915_WRITE(GEN8_GT_IMR(2), I915_READ(GEN8_GT_IMR(2)) |
> +					   dev_priv->pm_irq_mask);
> +		POSTING_READ(GEN8_GT_IMR(2));
> +	}
> +}
> +
> +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
> +{
> +	bdw_update_pm_irq(dev_priv, mask, mask);
> +}
> +
> +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
> +{
> +	bdw_update_pm_irq(dev_priv, mask, 0);
> +}
> +
> +

Unnecessary empty line.

>  static bool cpt_can_enable_serr_int(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -1126,13 +1170,17 @@ static void gen6_pm_rps_work(struct work_struct *work)
>  	spin_lock_irq(&dev_priv->irq_lock);
>  	pm_iir = dev_priv->rps.pm_iir;
>  	dev_priv->rps.pm_iir = 0;
> -	/* Make sure not to corrupt PMIMR state used by ringbuffer code */
> -	snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> +	if (IS_BROADWELL(dev_priv->dev))
> +		bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> +	else {
> +		/* Make sure not to corrupt PMIMR state used by ringbuffer */
> +		snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> +		/* Make sure we didn't queue anything we're not going to
> +		 * process. */
> +		WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
> +	}
>  	spin_unlock_irq(&dev_priv->irq_lock);
>  
> -	/* Make sure we didn't queue anything we're not going to process. */
> -	WARN_ON(pm_iir & ~dev_priv->pm_rps_events);

Isn't this WARN equally valid for bdw?

> -
>  	if ((pm_iir & dev_priv->pm_rps_events) == 0)
>  		return;
>  
> @@ -1324,6 +1372,19 @@ static void snb_gt_irq_handler(struct drm_device *dev,
>  		ivybridge_parity_error_irq_handler(dev, gt_iir);
>  }
>  
> +static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
> +{
> +	if ((pm_iir & dev_priv->pm_rps_events) == 0)
> +		return;
> +
> +	spin_lock(&dev_priv->irq_lock);
> +	dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
> +	bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
> +	spin_unlock(&dev_priv->irq_lock);
> +
> +	queue_work(dev_priv->wq, &dev_priv->rps.work);
> +}
> +
>  static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>  				       struct drm_i915_private *dev_priv,
>  				       u32 master_ctl)
> @@ -1359,6 +1420,16 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>  			DRM_ERROR("The master control interrupt lied (GT1)!\n");
>  	}
>  
> +	if (master_ctl & GEN8_GT_PM_IRQ) {
> +		tmp = I915_READ(GEN8_GT_IIR(2));
> +		if (tmp & dev_priv->pm_rps_events) {
> +			ret = IRQ_HANDLED;
> +			gen8_rps_irq_handler(dev_priv, tmp);
> +			I915_WRITE(GEN8_GT_IIR(1), tmp & dev_priv->pm_rps_events);
                                   ^^^^^^^^^^^^^^

GEN8_GT_IIR(2)

> +		} else
> +			DRM_ERROR("The master control interrupt lied (PM)!\n");
> +	}
> +
>  	if (master_ctl & GEN8_GT_VECS_IRQ) {
>  		tmp = I915_READ(GEN8_GT_IIR(3));
>  		if (tmp) {
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 8f84555..c2dd436 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -4193,6 +4193,7 @@ enum punit_power_well {
>  #define  GEN8_DE_PIPE_A_IRQ		(1<<16)
>  #define  GEN8_DE_PIPE_IRQ(pipe)		(1<<(16+pipe))
>  #define  GEN8_GT_VECS_IRQ		(1<<6)
> +#define  GEN8_GT_PM_IRQ			(1<<4)
>  #define  GEN8_GT_VCS2_IRQ		(1<<3)
>  #define  GEN8_GT_VCS1_IRQ		(1<<2)
>  #define  GEN8_GT_BCS_IRQ		(1<<1)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index c551472..68a078c 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -650,10 +650,11 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>  void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>  void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>  void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>  void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
>  void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
>  
> -

Unrelated whitespace change. IIRC someone left these two empty lines
here on purpose.

>  /* intel_crt.c */
>  void intel_crt_init(struct drm_device *dev);
>  
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 75c1c76..27b64ab 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3210,6 +3210,25 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
>  	trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
>  }
>  
> +static void gen8_disable_rps_interrupts(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +
> +	I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
> +	I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
> +				   ~dev_priv->pm_rps_events);
> +	/* 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. */

This comment would need a bit of update for gen8.

> +
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	dev_priv->rps.pm_iir = 0;
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +
> +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
> +}
> +
>  static void gen6_disable_rps_interrupts(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -3236,7 +3255,10 @@ static void gen6_disable_rps(struct drm_device *dev)
>  	I915_WRITE(GEN6_RC_CONTROL, 0);
>  	I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
>  
> -	gen6_disable_rps_interrupts(dev);
> +	if (IS_BROADWELL(dev))
> +		gen8_disable_rps_interrupts(dev);
> +	else
> +		gen6_disable_rps_interrupts(dev);
>  }
>  
>  static void valleyview_disable_rps(struct drm_device *dev)
> @@ -3276,6 +3298,18 @@ int intel_enable_rc6(const struct drm_device *dev)
>  	return INTEL_RC6_ENABLE;
>  }
>  
> +static void gen8_enable_rps_interrupts(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	WARN_ON(dev_priv->rps.pm_iir);
> +	bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);

The order of "unmask first then clear" seems just wrong. The same issues is
already present in the gen6 code however. So this should be fixed in
both places, or if it's like that on purpose it needs a comment.

> +	spin_unlock_irq(&dev_priv->irq_lock);
> +

Useless empty line.

> +}
> +
>  static void gen6_enable_rps_interrupts(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -3378,7 +3412,7 @@ static void gen8_enable_rps(struct drm_device *dev)
>  
>  	gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8);
>  
> -	gen6_enable_rps_interrupts(dev);
> +	gen8_enable_rps_interrupts(dev);
>  
>  	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
>  }
> -- 
> 1.8.5.2
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC

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

* Re: [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler
  2014-04-14 19:55   ` Ville Syrjälä
@ 2014-04-16  2:43     ` Ben Widawsky
  2014-04-16  7:47       ` Daniel Vetter
  2014-04-16  8:41       ` Ville Syrjälä
  0 siblings, 2 replies; 12+ messages in thread
From: Ben Widawsky @ 2014-04-16  2:43 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: deepak.s, intel-gfx, Ben Widawsky

On Mon, Apr 14, 2014 at 10:55:53PM +0300, Ville Syrjälä wrote:
> On Mon, Apr 14, 2014 at 10:41:14PM +0530, deepak.s@intel.com wrote:
> > From: Ben Widawsky <benjamin.widawsky@intel.com>
> > 
> > Almost all of it is reusable from the existing code. The primary
> > difference is we need to do even less in the interrupt handler, since
> > interrupts are not shared in the same way.
> > 
> > The patch is mostly a copy-paste of the existing snb+ code, with updates
> > to the relevant parts requiring changes to the interrupt handling. As
> > such it /should/ be relatively trivial. It's highly likely that I missed
> > some places where I need a gen8 version of the PM interrupts, but it has
> > become invisible to me by now.
> > 
> > This patch could probably be split into adding the new functions,
> > followed by actually handling the interrupts. Since the code is
> > currently disabled (and broken) I think the patch stands better by
> > itself.
> > 
> > v2: Move the commit about not touching the ringbuffer interrupt to the
> > snb_* function where it belongs (Rodrigo)
> > 
> > v3: Rebased on Paulo's runtime PM changes
> > 
> > v4: Not well validated, but rebase on
> > commit 730488b2eddded4497f63f70867b1256cd9e117c
> > Author: Paulo Zanoni <paulo.r.zanoni@intel.com>
> > Date:   Fri Mar 7 20:12:32 2014 -0300
> > 
> >     drm/i915: kill dev_priv->pm.regsave
> > 
> > v5: Rebased on latest code base. (Deepak)
> > 
> > Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
> > 
> > Conflicts:
> > 	drivers/gpu/drm/i915/i915_irq.c
> 
> IIRC Daniel doesn't like these conflict markers. So should be dropped.
> 

I like the conflict markers generally. Daniel can kill it if he likes,
but thanks for the input. I've killed it this time around, but I don't
plan on it for the future.

> > ---
> >  drivers/gpu/drm/i915/i915_irq.c  | 81 +++++++++++++++++++++++++++++++++++++---
> >  drivers/gpu/drm/i915/i915_reg.h  |  1 +
> >  drivers/gpu/drm/i915/intel_drv.h |  3 +-
> >  drivers/gpu/drm/i915/intel_pm.c  | 38 ++++++++++++++++++-
> >  4 files changed, 115 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index 7a4d3ae..96c459a 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -248,6 +248,50 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
> >  	return true;
> >  }
> >  
> > +/**
> > +  * bdw_update_pm_irq - update GT interrupt 2
> > +  * @dev_priv: driver private
> > +  * @interrupt_mask: mask of interrupt bits to update
> > +  * @enabled_irq_mask: mask of interrupt bits to enable
> > +  *
> > +  * Copied from the snb function, updated with relevant register offsets
> > +  */
> > +static void bdw_update_pm_irq(struct drm_i915_private *dev_priv,
> > +			      uint32_t interrupt_mask,
> > +			      uint32_t enabled_irq_mask)
> > +{
> > +	uint32_t new_val;
> > +
> > +	assert_spin_locked(&dev_priv->irq_lock);
> > +
> > +	if (dev_priv->pm.irqs_disabled) {
> > +		WARN(1, "IRQs disabled\n");
> > +		return;
> > +	}
> > +
> > +	new_val = dev_priv->pm_irq_mask;
> > +	new_val &= ~interrupt_mask;
> > +	new_val |= (~enabled_irq_mask & interrupt_mask);
> > +
> > +	if (new_val != dev_priv->pm_irq_mask) {
> > +		dev_priv->pm_irq_mask = new_val;
> > +		I915_WRITE(GEN8_GT_IMR(2), I915_READ(GEN8_GT_IMR(2)) |
> > +					   dev_priv->pm_irq_mask);
> > +		POSTING_READ(GEN8_GT_IMR(2));
> > +	}
> > +}
> > +
> > +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
> > +{
> > +	bdw_update_pm_irq(dev_priv, mask, mask);
> > +}
> > +
> > +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
> > +{
> > +	bdw_update_pm_irq(dev_priv, mask, 0);
> > +}
> > +
> > +
> 
> Unnecessary empty line.
> 

Got it, thanks.

> >  static bool cpt_can_enable_serr_int(struct drm_device *dev)
> >  {
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -1126,13 +1170,17 @@ static void gen6_pm_rps_work(struct work_struct *work)
> >  	spin_lock_irq(&dev_priv->irq_lock);
> >  	pm_iir = dev_priv->rps.pm_iir;
> >  	dev_priv->rps.pm_iir = 0;
> > -	/* Make sure not to corrupt PMIMR state used by ringbuffer code */
> > -	snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> > +	if (IS_BROADWELL(dev_priv->dev))
> > +		bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> > +	else {
> > +		/* Make sure not to corrupt PMIMR state used by ringbuffer */
> > +		snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> > +		/* Make sure we didn't queue anything we're not going to
> > +		 * process. */
> > +		WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
> > +	}
> >  	spin_unlock_irq(&dev_priv->irq_lock);
> >  
> > -	/* Make sure we didn't queue anything we're not going to process. */
> > -	WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
> 
> Isn't this WARN equally valid for bdw?
> 

So first, let me just mention, this has moved slightly in my latest
version of this patch, but it's still a valid question.

The answer is ambiguous actually. The WARN is always valid technically
The distinction in BDW (at least for the time being) is that unlike
pre-BDW, PM IIR isn't shared. I can add it, but for BDW, at least right
now, DRM_ERROR (or BUG) is more appropriate.


> > -
> >  	if ((pm_iir & dev_priv->pm_rps_events) == 0)
> >  		return;
> >  
> > @@ -1324,6 +1372,19 @@ static void snb_gt_irq_handler(struct drm_device *dev,
> >  		ivybridge_parity_error_irq_handler(dev, gt_iir);
> >  }
> >  
> > +static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
> > +{
> > +	if ((pm_iir & dev_priv->pm_rps_events) == 0)
> > +		return;
> > +
> > +	spin_lock(&dev_priv->irq_lock);
> > +	dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
> > +	bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
> > +	spin_unlock(&dev_priv->irq_lock);
> > +
> > +	queue_work(dev_priv->wq, &dev_priv->rps.work);
> > +}
> > +
> >  static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
> >  				       struct drm_i915_private *dev_priv,
> >  				       u32 master_ctl)
> > @@ -1359,6 +1420,16 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
> >  			DRM_ERROR("The master control interrupt lied (GT1)!\n");
> >  	}
> >  
> > +	if (master_ctl & GEN8_GT_PM_IRQ) {
> > +		tmp = I915_READ(GEN8_GT_IIR(2));
> > +		if (tmp & dev_priv->pm_rps_events) {
> > +			ret = IRQ_HANDLED;
> > +			gen8_rps_irq_handler(dev_priv, tmp);
> > +			I915_WRITE(GEN8_GT_IIR(1), tmp & dev_priv->pm_rps_events);
>                                    ^^^^^^^^^^^^^^
> 
> GEN8_GT_IIR(2)
> 

Nice catch, I guess I need to retest after this one.

> > +		} else
> > +			DRM_ERROR("The master control interrupt lied (PM)!\n");
> > +	}
> > +
> >  	if (master_ctl & GEN8_GT_VECS_IRQ) {
> >  		tmp = I915_READ(GEN8_GT_IIR(3));
> >  		if (tmp) {
> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > index 8f84555..c2dd436 100644
> > --- a/drivers/gpu/drm/i915/i915_reg.h
> > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > @@ -4193,6 +4193,7 @@ enum punit_power_well {
> >  #define  GEN8_DE_PIPE_A_IRQ		(1<<16)
> >  #define  GEN8_DE_PIPE_IRQ(pipe)		(1<<(16+pipe))
> >  #define  GEN8_GT_VECS_IRQ		(1<<6)
> > +#define  GEN8_GT_PM_IRQ			(1<<4)
> >  #define  GEN8_GT_VCS2_IRQ		(1<<3)
> >  #define  GEN8_GT_VCS1_IRQ		(1<<2)
> >  #define  GEN8_GT_BCS_IRQ		(1<<1)
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index c551472..68a078c 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -650,10 +650,11 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> >  void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> >  void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> >  void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> > +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> > +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> >  void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
> >  void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
> >  
> > -
> 
> Unrelated whitespace change. IIRC someone left these two empty lines
> here on purpose.
> 

Got it, thanks.

> >  /* intel_crt.c */
> >  void intel_crt_init(struct drm_device *dev);
> >  
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index 75c1c76..27b64ab 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -3210,6 +3210,25 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
> >  	trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
> >  }
> >  
> > +static void gen8_disable_rps_interrupts(struct drm_device *dev)
> > +{
> > +	struct drm_i915_private *dev_priv = dev->dev_private;
> > +
> > +	I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
> > +	I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
> > +				   ~dev_priv->pm_rps_events);
> > +	/* 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. */
> 
> This comment would need a bit of update for gen8.
> 

I've killed this comment locally. Somewhere I had written that we can
rewrite some of this for gen8, but I seem to have lost that in the sands
of time.

> > +
> > +	spin_lock_irq(&dev_priv->irq_lock);
> > +	dev_priv->rps.pm_iir = 0;
> > +	spin_unlock_irq(&dev_priv->irq_lock);
> > +
> > +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
> > +}
> > +
> >  static void gen6_disable_rps_interrupts(struct drm_device *dev)
> >  {
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -3236,7 +3255,10 @@ static void gen6_disable_rps(struct drm_device *dev)
> >  	I915_WRITE(GEN6_RC_CONTROL, 0);
> >  	I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
> >  
> > -	gen6_disable_rps_interrupts(dev);
> > +	if (IS_BROADWELL(dev))
> > +		gen8_disable_rps_interrupts(dev);
> > +	else
> > +		gen6_disable_rps_interrupts(dev);
> >  }
> >  
> >  static void valleyview_disable_rps(struct drm_device *dev)
> > @@ -3276,6 +3298,18 @@ int intel_enable_rc6(const struct drm_device *dev)
> >  	return INTEL_RC6_ENABLE;
> >  }
> >  
> > +static void gen8_enable_rps_interrupts(struct drm_device *dev)
> > +{
> > +	struct drm_i915_private *dev_priv = dev->dev_private;
> > +
> > +	spin_lock_irq(&dev_priv->irq_lock);
> > +	WARN_ON(dev_priv->rps.pm_iir);
> > +	bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> > +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
> 
> The order of "unmask first then clear" seems just wrong. The same issues is
> already present in the gen6 code however. So this should be fixed in
> both places, or if it's like that on purpose it needs a comment.
> 

Well, if you want to fix it, we can do it in a separate patch. Although
I don't think I agree. Why does it seem wrong to you?

> > +	spin_unlock_irq(&dev_priv->irq_lock);
> > +
> 
> Useless empty line.
> 

If I was in an arguing mood, I would do, but fine.

> > +}
> > +
> >  static void gen6_enable_rps_interrupts(struct drm_device *dev)
> >  {
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -3378,7 +3412,7 @@ static void gen8_enable_rps(struct drm_device *dev)
> >  
> >  	gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8);
> >  
> > -	gen6_enable_rps_interrupts(dev);
> > +	gen8_enable_rps_interrupts(dev);
> >  
> >  	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
> >  }

Thanks for the review.

-- 
Ben Widawsky, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler
  2014-04-16  2:43     ` Ben Widawsky
@ 2014-04-16  7:47       ` Daniel Vetter
  2014-04-16  8:41       ` Ville Syrjälä
  1 sibling, 0 replies; 12+ messages in thread
From: Daniel Vetter @ 2014-04-16  7:47 UTC (permalink / raw)
  To: Ben Widawsky; +Cc: deepak.s, intel-gfx, Ben Widawsky

On Tue, Apr 15, 2014 at 07:43:07PM -0700, Ben Widawsky wrote:
> On Mon, Apr 14, 2014 at 10:55:53PM +0300, Ville Syrjälä wrote:
> > On Mon, Apr 14, 2014 at 10:41:14PM +0530, deepak.s@intel.com wrote:
> > > From: Ben Widawsky <benjamin.widawsky@intel.com>
> > > 
> > > Almost all of it is reusable from the existing code. The primary
> > > difference is we need to do even less in the interrupt handler, since
> > > interrupts are not shared in the same way.
> > > 
> > > The patch is mostly a copy-paste of the existing snb+ code, with updates
> > > to the relevant parts requiring changes to the interrupt handling. As
> > > such it /should/ be relatively trivial. It's highly likely that I missed
> > > some places where I need a gen8 version of the PM interrupts, but it has
> > > become invisible to me by now.
> > > 
> > > This patch could probably be split into adding the new functions,
> > > followed by actually handling the interrupts. Since the code is
> > > currently disabled (and broken) I think the patch stands better by
> > > itself.
> > > 
> > > v2: Move the commit about not touching the ringbuffer interrupt to the
> > > snb_* function where it belongs (Rodrigo)
> > > 
> > > v3: Rebased on Paulo's runtime PM changes
> > > 
> > > v4: Not well validated, but rebase on
> > > commit 730488b2eddded4497f63f70867b1256cd9e117c
> > > Author: Paulo Zanoni <paulo.r.zanoni@intel.com>
> > > Date:   Fri Mar 7 20:12:32 2014 -0300
> > > 
> > >     drm/i915: kill dev_priv->pm.regsave
> > > 
> > > v5: Rebased on latest code base. (Deepak)
> > > 
> > > Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
> > > 
> > > Conflicts:
> > > 	drivers/gpu/drm/i915/i915_irq.c
> > 
> > IIRC Daniel doesn't like these conflict markers. So should be dropped.
> > 
> 
> I like the conflict markers generally. Daniel can kill it if he likes,
> but thanks for the input. I've killed it this time around, but I don't
> plan on it for the future.

Imo leaving them in is just lazy. Either there was some real conflict that
required real work, and then you should rev the patch revision and take
note about the changes in the in-patch changelog.

Or the conflict was trivial, in which case the left-behind marker is
meaningless and doesn't add anything useful to the commit message.

So please remove them and if it makes sense augment the patch revision
log. See e.g. the rebase notes (where I mention the upstream changes that
required the rebase) I add for -internal patches.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler
  2014-04-16  2:43     ` Ben Widawsky
  2014-04-16  7:47       ` Daniel Vetter
@ 2014-04-16  8:41       ` Ville Syrjälä
  2014-04-18 12:39         ` S, Deepak
  2014-04-18 12:40         ` S, Deepak
  1 sibling, 2 replies; 12+ messages in thread
From: Ville Syrjälä @ 2014-04-16  8:41 UTC (permalink / raw)
  To: Ben Widawsky; +Cc: deepak.s, intel-gfx, Ben Widawsky

On Tue, Apr 15, 2014 at 07:43:07PM -0700, Ben Widawsky wrote:
> On Mon, Apr 14, 2014 at 10:55:53PM +0300, Ville Syrjälä wrote:
> > On Mon, Apr 14, 2014 at 10:41:14PM +0530, deepak.s@intel.com wrote:
> > > From: Ben Widawsky <benjamin.widawsky@intel.com>
> > > 
> > > Almost all of it is reusable from the existing code. The primary
> > > difference is we need to do even less in the interrupt handler, since
> > > interrupts are not shared in the same way.
> > > 
> > > The patch is mostly a copy-paste of the existing snb+ code, with updates
> > > to the relevant parts requiring changes to the interrupt handling. As
> > > such it /should/ be relatively trivial. It's highly likely that I missed
> > > some places where I need a gen8 version of the PM interrupts, but it has
> > > become invisible to me by now.
> > > 
> > > This patch could probably be split into adding the new functions,
> > > followed by actually handling the interrupts. Since the code is
> > > currently disabled (and broken) I think the patch stands better by
> > > itself.
> > > 
> > > v2: Move the commit about not touching the ringbuffer interrupt to the
> > > snb_* function where it belongs (Rodrigo)
> > > 
> > > v3: Rebased on Paulo's runtime PM changes
> > > 
> > > v4: Not well validated, but rebase on
> > > commit 730488b2eddded4497f63f70867b1256cd9e117c
> > > Author: Paulo Zanoni <paulo.r.zanoni@intel.com>
> > > Date:   Fri Mar 7 20:12:32 2014 -0300
> > > 
> > >     drm/i915: kill dev_priv->pm.regsave
> > > 
> > > v5: Rebased on latest code base. (Deepak)
> > > 
> > > Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
> > > 
> > > Conflicts:
> > > 	drivers/gpu/drm/i915/i915_irq.c
> > 
> > IIRC Daniel doesn't like these conflict markers. So should be dropped.
> > 
> 
> I like the conflict markers generally. Daniel can kill it if he likes,
> but thanks for the input. I've killed it this time around, but I don't
> plan on it for the future.
> 
> > > ---
> > >  drivers/gpu/drm/i915/i915_irq.c  | 81 +++++++++++++++++++++++++++++++++++++---
> > >  drivers/gpu/drm/i915/i915_reg.h  |  1 +
> > >  drivers/gpu/drm/i915/intel_drv.h |  3 +-
> > >  drivers/gpu/drm/i915/intel_pm.c  | 38 ++++++++++++++++++-
> > >  4 files changed, 115 insertions(+), 8 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > > index 7a4d3ae..96c459a 100644
> > > --- a/drivers/gpu/drm/i915/i915_irq.c
> > > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > > @@ -248,6 +248,50 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
> > >  	return true;
> > >  }
> > >  
> > > +/**
> > > +  * bdw_update_pm_irq - update GT interrupt 2
> > > +  * @dev_priv: driver private
> > > +  * @interrupt_mask: mask of interrupt bits to update
> > > +  * @enabled_irq_mask: mask of interrupt bits to enable
> > > +  *
> > > +  * Copied from the snb function, updated with relevant register offsets
> > > +  */
> > > +static void bdw_update_pm_irq(struct drm_i915_private *dev_priv,
> > > +			      uint32_t interrupt_mask,
> > > +			      uint32_t enabled_irq_mask)
> > > +{
> > > +	uint32_t new_val;
> > > +
> > > +	assert_spin_locked(&dev_priv->irq_lock);
> > > +
> > > +	if (dev_priv->pm.irqs_disabled) {
> > > +		WARN(1, "IRQs disabled\n");
> > > +		return;
> > > +	}
> > > +
> > > +	new_val = dev_priv->pm_irq_mask;
> > > +	new_val &= ~interrupt_mask;
> > > +	new_val |= (~enabled_irq_mask & interrupt_mask);
> > > +
> > > +	if (new_val != dev_priv->pm_irq_mask) {
> > > +		dev_priv->pm_irq_mask = new_val;
> > > +		I915_WRITE(GEN8_GT_IMR(2), I915_READ(GEN8_GT_IMR(2)) |
> > > +					   dev_priv->pm_irq_mask);
> > > +		POSTING_READ(GEN8_GT_IMR(2));
> > > +	}
> > > +}
> > > +
> > > +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
> > > +{
> > > +	bdw_update_pm_irq(dev_priv, mask, mask);
> > > +}
> > > +
> > > +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
> > > +{
> > > +	bdw_update_pm_irq(dev_priv, mask, 0);
> > > +}
> > > +
> > > +
> > 
> > Unnecessary empty line.
> > 
> 
> Got it, thanks.
> 
> > >  static bool cpt_can_enable_serr_int(struct drm_device *dev)
> > >  {
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > > @@ -1126,13 +1170,17 @@ static void gen6_pm_rps_work(struct work_struct *work)
> > >  	spin_lock_irq(&dev_priv->irq_lock);
> > >  	pm_iir = dev_priv->rps.pm_iir;
> > >  	dev_priv->rps.pm_iir = 0;
> > > -	/* Make sure not to corrupt PMIMR state used by ringbuffer code */
> > > -	snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> > > +	if (IS_BROADWELL(dev_priv->dev))
> > > +		bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> > > +	else {
> > > +		/* Make sure not to corrupt PMIMR state used by ringbuffer */
> > > +		snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> > > +		/* Make sure we didn't queue anything we're not going to
> > > +		 * process. */
> > > +		WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
> > > +	}
> > >  	spin_unlock_irq(&dev_priv->irq_lock);
> > >  
> > > -	/* Make sure we didn't queue anything we're not going to process. */
> > > -	WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
> > 
> > Isn't this WARN equally valid for bdw?
> > 
> 
> So first, let me just mention, this has moved slightly in my latest
> version of this patch, but it's still a valid question.
> 
> The answer is ambiguous actually. The WARN is always valid technically
> The distinction in BDW (at least for the time being) is that unlike
> pre-BDW, PM IIR isn't shared. I can add it, but for BDW, at least right
> now, DRM_ERROR (or BUG) is more appropriate.

I don't see a reason for bdw to be different here. There are other bits
in the relevant IIR registers, so the same WARN should be fine.

> 
> 
> > > -
> > >  	if ((pm_iir & dev_priv->pm_rps_events) == 0)
> > >  		return;
> > >  
> > > @@ -1324,6 +1372,19 @@ static void snb_gt_irq_handler(struct drm_device *dev,
> > >  		ivybridge_parity_error_irq_handler(dev, gt_iir);
> > >  }
> > >  
> > > +static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
> > > +{
> > > +	if ((pm_iir & dev_priv->pm_rps_events) == 0)
> > > +		return;
> > > +
> > > +	spin_lock(&dev_priv->irq_lock);
> > > +	dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
> > > +	bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
> > > +	spin_unlock(&dev_priv->irq_lock);
> > > +
> > > +	queue_work(dev_priv->wq, &dev_priv->rps.work);
> > > +}
> > > +
> > >  static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
> > >  				       struct drm_i915_private *dev_priv,
> > >  				       u32 master_ctl)
> > > @@ -1359,6 +1420,16 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
> > >  			DRM_ERROR("The master control interrupt lied (GT1)!\n");
> > >  	}
> > >  
> > > +	if (master_ctl & GEN8_GT_PM_IRQ) {
> > > +		tmp = I915_READ(GEN8_GT_IIR(2));
> > > +		if (tmp & dev_priv->pm_rps_events) {
> > > +			ret = IRQ_HANDLED;
> > > +			gen8_rps_irq_handler(dev_priv, tmp);
> > > +			I915_WRITE(GEN8_GT_IIR(1), tmp & dev_priv->pm_rps_events);
> >                                    ^^^^^^^^^^^^^^
> > 
> > GEN8_GT_IIR(2)
> > 
> 
> Nice catch, I guess I need to retest after this one.

I'm actually wondering how/if you managed to test this before Deepak's
PMINTRMSK interrupt redirect bit fix. W/o that you shouldn't be
getting any interrupt AFAICS.

> 
> > > +		} else
> > > +			DRM_ERROR("The master control interrupt lied (PM)!\n");
> > > +	}
> > > +
> > >  	if (master_ctl & GEN8_GT_VECS_IRQ) {
> > >  		tmp = I915_READ(GEN8_GT_IIR(3));
> > >  		if (tmp) {
> > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > > index 8f84555..c2dd436 100644
> > > --- a/drivers/gpu/drm/i915/i915_reg.h
> > > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > > @@ -4193,6 +4193,7 @@ enum punit_power_well {
> > >  #define  GEN8_DE_PIPE_A_IRQ		(1<<16)
> > >  #define  GEN8_DE_PIPE_IRQ(pipe)		(1<<(16+pipe))
> > >  #define  GEN8_GT_VECS_IRQ		(1<<6)
> > > +#define  GEN8_GT_PM_IRQ			(1<<4)
> > >  #define  GEN8_GT_VCS2_IRQ		(1<<3)
> > >  #define  GEN8_GT_VCS1_IRQ		(1<<2)
> > >  #define  GEN8_GT_BCS_IRQ		(1<<1)
> > > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > > index c551472..68a078c 100644
> > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > @@ -650,10 +650,11 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> > >  void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> > >  void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> > >  void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> > > +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> > > +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> > >  void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
> > >  void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
> > >  
> > > -
> > 
> > Unrelated whitespace change. IIRC someone left these two empty lines
> > here on purpose.
> > 
> 
> Got it, thanks.
> 
> > >  /* intel_crt.c */
> > >  void intel_crt_init(struct drm_device *dev);
> > >  
> > > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > > index 75c1c76..27b64ab 100644
> > > --- a/drivers/gpu/drm/i915/intel_pm.c
> > > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > > @@ -3210,6 +3210,25 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
> > >  	trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
> > >  }
> > >  
> > > +static void gen8_disable_rps_interrupts(struct drm_device *dev)
> > > +{
> > > +	struct drm_i915_private *dev_priv = dev->dev_private;
> > > +
> > > +	I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
> > > +	I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
> > > +				   ~dev_priv->pm_rps_events);
> > > +	/* 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. */
> > 
> > This comment would need a bit of update for gen8.
> > 
> 
> I've killed this comment locally. Somewhere I had written that we can
> rewrite some of this for gen8, but I seem to have lost that in the sands
> of time.
> 
> > > +
> > > +	spin_lock_irq(&dev_priv->irq_lock);
> > > +	dev_priv->rps.pm_iir = 0;
> > > +	spin_unlock_irq(&dev_priv->irq_lock);
> > > +
> > > +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
> > > +}
> > > +
> > >  static void gen6_disable_rps_interrupts(struct drm_device *dev)
> > >  {
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > > @@ -3236,7 +3255,10 @@ static void gen6_disable_rps(struct drm_device *dev)
> > >  	I915_WRITE(GEN6_RC_CONTROL, 0);
> > >  	I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
> > >  
> > > -	gen6_disable_rps_interrupts(dev);
> > > +	if (IS_BROADWELL(dev))
> > > +		gen8_disable_rps_interrupts(dev);
> > > +	else
> > > +		gen6_disable_rps_interrupts(dev);
> > >  }
> > >  
> > >  static void valleyview_disable_rps(struct drm_device *dev)
> > > @@ -3276,6 +3298,18 @@ int intel_enable_rc6(const struct drm_device *dev)
> > >  	return INTEL_RC6_ENABLE;
> > >  }
> > >  
> > > +static void gen8_enable_rps_interrupts(struct drm_device *dev)
> > > +{
> > > +	struct drm_i915_private *dev_priv = dev->dev_private;
> > > +
> > > +	spin_lock_irq(&dev_priv->irq_lock);
> > > +	WARN_ON(dev_priv->rps.pm_iir);
> > > +	bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> > > +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
> > 
> > The order of "unmask first then clear" seems just wrong. The same issues is
> > already present in the gen6 code however. So this should be fixed in
> > both places, or if it's like that on purpose it needs a comment.
> > 
> 
> Well, if you want to fix it, we can do it in a separate patch. Although
> I don't think I agree. Why does it seem wrong to you?

If you enable before clearing and there's already an IIR bit high the
interrupt should trigger immediately before you get to clear it. And
then on a SMP machine the write to clear it would even race with the
interrupt handler if there's no locking. So the clearing after
enabling+unmasking is pointless. The normal approach for enabling
interrupts is to clear first and then enable.

Hmm. Actually here we alreay have the interrupts enabled in IER, so
if any relevant IIR bit would be high, we should have already gotten
the interrupt. But since we always clear the IIR after masking the
interrupts in IMR, we should never have any relevant IIR bit set here.

So looks to me like we can just drop the IIR writes here. They serve no
purpose other than racing with the interrupt handler if a real interrupt
happens just after we've unmasked it.

> 
> > > +	spin_unlock_irq(&dev_priv->irq_lock);
> > > +
> > 
> > Useless empty line.
> > 
> 
> If I was in an arguing mood, I would do, but fine.
> 
> > > +}
> > > +
> > >  static void gen6_enable_rps_interrupts(struct drm_device *dev)
> > >  {
> > >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > > @@ -3378,7 +3412,7 @@ static void gen8_enable_rps(struct drm_device *dev)
> > >  
> > >  	gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8);
> > >  
> > > -	gen6_enable_rps_interrupts(dev);
> > > +	gen8_enable_rps_interrupts(dev);
> > >  
> > >  	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
> > >  }
> 
> Thanks for the review.
> 
> -- 
> Ben Widawsky, Intel Open Source Technology Center

-- 
Ville Syrjälä
Intel OTC

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

* Re: [PATCH 2/2] drm/i915: Enable PM Interrupts target via Display Interface.
  2014-04-14 19:36   ` Ville Syrjälä
@ 2014-04-16 13:32     ` Ville Syrjälä
  2014-04-18  8:20       ` Deepak S
  0 siblings, 1 reply; 12+ messages in thread
From: Ville Syrjälä @ 2014-04-16 13:32 UTC (permalink / raw)
  To: deepak.s; +Cc: intel-gfx

On Mon, Apr 14, 2014 at 10:36:55PM +0300, Ville Syrjälä wrote:
> On Mon, Apr 14, 2014 at 10:41:15PM +0530, deepak.s@intel.com wrote:
> > From: Deepak S <deepak.s@intel.com>
> > 
> > In BDW, Apart from unmasking up/down threshold interrupts. we need
> > to umask bit 32 of PM_INTRMASK to route interrupts to target via Display
> > Interface.
> > 
> > Signed-off-by: Deepak S <deepak.s@intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_reg.h | 1 +
> >  drivers/gpu/drm/i915/intel_pm.c | 2 ++
> >  2 files changed, 3 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > index c2dd436..8c7841b 100644
> > --- a/drivers/gpu/drm/i915/i915_reg.h
> > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > @@ -5105,6 +5105,7 @@ enum punit_power_well {
> >  #define GEN6_RC6p_THRESHOLD			0xA0BC
> >  #define GEN6_RC6pp_THRESHOLD			0xA0C0
> >  #define GEN6_PMINTRMSK				0xA168
> > +#define GEN8_PMINTR_REDIRECT_TO_NON_DISP	0x7FFFFFFF
> 
> Defining is as (1<<31) would make more sense to me.
> 
> >  
> >  #define GEN6_PMISR				0x44020
> >  #define GEN6_PMIMR				0x44024 /* rps_lock */
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index 27b64ab..6b123cd 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -3066,6 +3066,8 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
> >  	if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev))
> >  		mask |= GEN6_PM_RP_UP_EI_EXPIRED;
> >  
> > +	mask &= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
> > +
> >  	return ~mask;

Oh and just noticed this doesn't actually do anything.
& must come after ~ to get the expected result.

> >  }
> >  
> > -- 
> > 1.8.5.2
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Ville Syrjälä
> Intel OTC

-- 
Ville Syrjälä
Intel OTC

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

* Re: [PATCH 2/2] drm/i915: Enable PM Interrupts target via Display Interface.
  2014-04-16 13:32     ` Ville Syrjälä
@ 2014-04-18  8:20       ` Deepak S
  0 siblings, 0 replies; 12+ messages in thread
From: Deepak S @ 2014-04-18  8:20 UTC (permalink / raw)
  To: Ville Syrjälä, deepak.s; +Cc: intel-gfx


On Wednesday 16 April 2014 07:02 PM, Ville Syrjälä wrote:
> On Mon, Apr 14, 2014 at 10:36:55PM +0300, Ville Syrjälä wrote:
>> On Mon, Apr 14, 2014 at 10:41:15PM +0530, deepak.s@intel.com wrote:
>>> From: Deepak S <deepak.s@intel.com>
>>>
>>> In BDW, Apart from unmasking up/down threshold interrupts. we need
>>> to umask bit 32 of PM_INTRMASK to route interrupts to target via Display
>>> Interface.
>>>
>>> Signed-off-by: Deepak S <deepak.s@intel.com>
>>> ---
>>>   drivers/gpu/drm/i915/i915_reg.h | 1 +
>>>   drivers/gpu/drm/i915/intel_pm.c | 2 ++
>>>   2 files changed, 3 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>>> index c2dd436..8c7841b 100644
>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>> @@ -5105,6 +5105,7 @@ enum punit_power_well {
>>>   #define GEN6_RC6p_THRESHOLD			0xA0BC
>>>   #define GEN6_RC6pp_THRESHOLD			0xA0C0
>>>   #define GEN6_PMINTRMSK				0xA168
>>> +#define GEN8_PMINTR_REDIRECT_TO_NON_DISP	0x7FFFFFFF
>> Defining is as (1<<31) would make more sense to me.
>>
>>>   
>>>   #define GEN6_PMISR				0x44020
>>>   #define GEN6_PMIMR				0x44024 /* rps_lock */
>>> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
>>> index 27b64ab..6b123cd 100644
>>> --- a/drivers/gpu/drm/i915/intel_pm.c
>>> +++ b/drivers/gpu/drm/i915/intel_pm.c
>>> @@ -3066,6 +3066,8 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
>>>   	if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev))
>>>   		mask |= GEN6_PM_RP_UP_EI_EXPIRED;
>>>   
>>> +	mask &= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
>>> +
>>>   	return ~mask;
> Oh and just noticed this doesn't actually do anything.
> & must come after ~ to get the expected result.
>
>>>   }
>>>   
>>> -- 
>>> 1.8.5.2
>>>
>>> _______________________________________________
>>> Intel-gfx mailing list
>>> Intel-gfx@lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>> -- 
>> Ville Syrjälä
>> Intel OTC

Thanks for review

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

* Re: [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler
  2014-04-16  8:41       ` Ville Syrjälä
@ 2014-04-18 12:39         ` S, Deepak
  2014-04-18 12:40         ` S, Deepak
  1 sibling, 0 replies; 12+ messages in thread
From: S, Deepak @ 2014-04-18 12:39 UTC (permalink / raw)
  To: Ville Syrjälä, Ben Widawsky; +Cc: intel-gfx, Ben Widawsky



On 4/16/2014 2:11 PM, Ville Syrjälä wrote:
> On Tue, Apr 15, 2014 at 07:43:07PM -0700, Ben Widawsky wrote:
>> On Mon, Apr 14, 2014 at 10:55:53PM +0300, Ville Syrjälä wrote:
>>> On Mon, Apr 14, 2014 at 10:41:14PM +0530, deepak.s@intel.com wrote:
>>>> From: Ben Widawsky <benjamin.widawsky@intel.com>
>>>>
>>>> Almost all of it is reusable from the existing code. The primary
>>>> difference is we need to do even less in the interrupt handler, since
>>>> interrupts are not shared in the same way.
>>>>
>>>> The patch is mostly a copy-paste of the existing snb+ code, with updates
>>>> to the relevant parts requiring changes to the interrupt handling. As
>>>> such it /should/ be relatively trivial. It's highly likely that I missed
>>>> some places where I need a gen8 version of the PM interrupts, but it has
>>>> become invisible to me by now.
>>>>
>>>> This patch could probably be split into adding the new functions,
>>>> followed by actually handling the interrupts. Since the code is
>>>> currently disabled (and broken) I think the patch stands better by
>>>> itself.
>>>>
>>>> v2: Move the commit about not touching the ringbuffer interrupt to the
>>>> snb_* function where it belongs (Rodrigo)
>>>>
>>>> v3: Rebased on Paulo's runtime PM changes
>>>>
>>>> v4: Not well validated, but rebase on
>>>> commit 730488b2eddded4497f63f70867b1256cd9e117c
>>>> Author: Paulo Zanoni <paulo.r.zanoni@intel.com>
>>>> Date:   Fri Mar 7 20:12:32 2014 -0300
>>>>
>>>>      drm/i915: kill dev_priv->pm.regsave
>>>>
>>>> v5: Rebased on latest code base. (Deepak)
>>>>
>>>> Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
>>>>
>>>> Conflicts:
>>>> 	drivers/gpu/drm/i915/i915_irq.c
>>>
>>> IIRC Daniel doesn't like these conflict markers. So should be dropped.
>>>
>>
>> I like the conflict markers generally. Daniel can kill it if he likes,
>> but thanks for the input. I've killed it this time around, but I don't
>> plan on it for the future.
>>
>>>> ---
>>>>   drivers/gpu/drm/i915/i915_irq.c  | 81 +++++++++++++++++++++++++++++++++++++---
>>>>   drivers/gpu/drm/i915/i915_reg.h  |  1 +
>>>>   drivers/gpu/drm/i915/intel_drv.h |  3 +-
>>>>   drivers/gpu/drm/i915/intel_pm.c  | 38 ++++++++++++++++++-
>>>>   4 files changed, 115 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
>>>> index 7a4d3ae..96c459a 100644
>>>> --- a/drivers/gpu/drm/i915/i915_irq.c
>>>> +++ b/drivers/gpu/drm/i915/i915_irq.c
>>>> @@ -248,6 +248,50 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
>>>>   	return true;
>>>>   }
>>>>
>>>> +/**
>>>> +  * bdw_update_pm_irq - update GT interrupt 2
>>>> +  * @dev_priv: driver private
>>>> +  * @interrupt_mask: mask of interrupt bits to update
>>>> +  * @enabled_irq_mask: mask of interrupt bits to enable
>>>> +  *
>>>> +  * Copied from the snb function, updated with relevant register offsets
>>>> +  */
>>>> +static void bdw_update_pm_irq(struct drm_i915_private *dev_priv,
>>>> +			      uint32_t interrupt_mask,
>>>> +			      uint32_t enabled_irq_mask)
>>>> +{
>>>> +	uint32_t new_val;
>>>> +
>>>> +	assert_spin_locked(&dev_priv->irq_lock);
>>>> +
>>>> +	if (dev_priv->pm.irqs_disabled) {
>>>> +		WARN(1, "IRQs disabled\n");
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	new_val = dev_priv->pm_irq_mask;
>>>> +	new_val &= ~interrupt_mask;
>>>> +	new_val |= (~enabled_irq_mask & interrupt_mask);
>>>> +
>>>> +	if (new_val != dev_priv->pm_irq_mask) {
>>>> +		dev_priv->pm_irq_mask = new_val;
>>>> +		I915_WRITE(GEN8_GT_IMR(2), I915_READ(GEN8_GT_IMR(2)) |
>>>> +					   dev_priv->pm_irq_mask);
>>>> +		POSTING_READ(GEN8_GT_IMR(2));
>>>> +	}
>>>> +}
>>>> +
>>>> +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
>>>> +{
>>>> +	bdw_update_pm_irq(dev_priv, mask, mask);
>>>> +}
>>>> +
>>>> +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
>>>> +{
>>>> +	bdw_update_pm_irq(dev_priv, mask, 0);
>>>> +}
>>>> +
>>>> +
>>>
>>> Unnecessary empty line.
>>>
>>
>> Got it, thanks.
>>
>>>>   static bool cpt_can_enable_serr_int(struct drm_device *dev)
>>>>   {
>>>>   	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> @@ -1126,13 +1170,17 @@ static void gen6_pm_rps_work(struct work_struct *work)
>>>>   	spin_lock_irq(&dev_priv->irq_lock);
>>>>   	pm_iir = dev_priv->rps.pm_iir;
>>>>   	dev_priv->rps.pm_iir = 0;
>>>> -	/* Make sure not to corrupt PMIMR state used by ringbuffer code */
>>>> -	snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>>>> +	if (IS_BROADWELL(dev_priv->dev))
>>>> +		bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>>>> +	else {
>>>> +		/* Make sure not to corrupt PMIMR state used by ringbuffer */
>>>> +		snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>>>> +		/* Make sure we didn't queue anything we're not going to
>>>> +		 * process. */
>>>> +		WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
>>>> +	}
>>>>   	spin_unlock_irq(&dev_priv->irq_lock);
>>>>
>>>> -	/* Make sure we didn't queue anything we're not going to process. */
>>>> -	WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
>>>
>>> Isn't this WARN equally valid for bdw?
>>>
>>
>> So first, let me just mention, this has moved slightly in my latest
>> version of this patch, but it's still a valid question.
>>
>> The answer is ambiguous actually. The WARN is always valid technically
>> The distinction in BDW (at least for the time being) is that unlike
>> pre-BDW, PM IIR isn't shared. I can add it, but for BDW, at least right
>> now, DRM_ERROR (or BUG) is more appropriate.
>
> I don't see a reason for bdw to be different here. There are other bits
> in the relevant IIR registers, so the same WARN should be fine.
>
>>
>>
>>>> -
>>>>   	if ((pm_iir & dev_priv->pm_rps_events) == 0)
>>>>   		return;
>>>>
>>>> @@ -1324,6 +1372,19 @@ static void snb_gt_irq_handler(struct drm_device *dev,
>>>>   		ivybridge_parity_error_irq_handler(dev, gt_iir);
>>>>   }
>>>>
>>>> +static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
>>>> +{
>>>> +	if ((pm_iir & dev_priv->pm_rps_events) == 0)
>>>> +		return;
>>>> +
>>>> +	spin_lock(&dev_priv->irq_lock);
>>>> +	dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
>>>> +	bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
>>>> +	spin_unlock(&dev_priv->irq_lock);
>>>> +
>>>> +	queue_work(dev_priv->wq, &dev_priv->rps.work);
>>>> +}
>>>> +
>>>>   static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>>>>   				       struct drm_i915_private *dev_priv,
>>>>   				       u32 master_ctl)
>>>> @@ -1359,6 +1420,16 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>>>>   			DRM_ERROR("The master control interrupt lied (GT1)!\n");
>>>>   	}
>>>>
>>>> +	if (master_ctl & GEN8_GT_PM_IRQ) {
>>>> +		tmp = I915_READ(GEN8_GT_IIR(2));
>>>> +		if (tmp & dev_priv->pm_rps_events) {
>>>> +			ret = IRQ_HANDLED;
>>>> +			gen8_rps_irq_handler(dev_priv, tmp);
>>>> +			I915_WRITE(GEN8_GT_IIR(1), tmp & dev_priv->pm_rps_events);
>>>                                     ^^^^^^^^^^^^^^
>>>
>>> GEN8_GT_IIR(2)
>>>
>>
>> Nice catch, I guess I need to retest after this one.
>
> I'm actually wondering how/if you managed to test this before Deepak's
> PMINTRMSK interrupt redirect bit fix. W/o that you shouldn't be
> getting any interrupt AFAICS.
>
>>
>>>> +		} else
>>>> +			DRM_ERROR("The master control interrupt lied (PM)!\n");
>>>> +	}
>>>> +
>>>>   	if (master_ctl & GEN8_GT_VECS_IRQ) {
>>>>   		tmp = I915_READ(GEN8_GT_IIR(3));
>>>>   		if (tmp) {
>>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>>>> index 8f84555..c2dd436 100644
>>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>>> @@ -4193,6 +4193,7 @@ enum punit_power_well {
>>>>   #define  GEN8_DE_PIPE_A_IRQ		(1<<16)
>>>>   #define  GEN8_DE_PIPE_IRQ(pipe)		(1<<(16+pipe))
>>>>   #define  GEN8_GT_VECS_IRQ		(1<<6)
>>>> +#define  GEN8_GT_PM_IRQ			(1<<4)
>>>>   #define  GEN8_GT_VCS2_IRQ		(1<<3)
>>>>   #define  GEN8_GT_VCS1_IRQ		(1<<2)
>>>>   #define  GEN8_GT_BCS_IRQ		(1<<1)
>>>> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>>>> index c551472..68a078c 100644
>>>> --- a/drivers/gpu/drm/i915/intel_drv.h
>>>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>>>> @@ -650,10 +650,11 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>>   void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>>   void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>>   void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>> +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>> +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>>   void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
>>>>   void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
>>>>
>>>> -
>>>
>>> Unrelated whitespace change. IIRC someone left these two empty lines
>>> here on purpose.
>>>
>>
>> Got it, thanks.
>>
>>>>   /* intel_crt.c */
>>>>   void intel_crt_init(struct drm_device *dev);
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
>>>> index 75c1c76..27b64ab 100644
>>>> --- a/drivers/gpu/drm/i915/intel_pm.c
>>>> +++ b/drivers/gpu/drm/i915/intel_pm.c
>>>> @@ -3210,6 +3210,25 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
>>>>   	trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
>>>>   }
>>>>
>>>> +static void gen8_disable_rps_interrupts(struct drm_device *dev)
>>>> +{
>>>> +	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> +
>>>> +	I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
>>>> +	I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
>>>> +				   ~dev_priv->pm_rps_events);
>>>> +	/* 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. */
>>>
>>> This comment would need a bit of update for gen8.
>>>
>>
>> I've killed this comment locally. Somewhere I had written that we can
>> rewrite some of this for gen8, but I seem to have lost that in the sands
>> of time.
>>
>>>> +
>>>> +	spin_lock_irq(&dev_priv->irq_lock);
>>>> +	dev_priv->rps.pm_iir = 0;
>>>> +	spin_unlock_irq(&dev_priv->irq_lock);
>>>> +
>>>> +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
>>>> +}
>>>> +
>>>>   static void gen6_disable_rps_interrupts(struct drm_device *dev)
>>>>   {
>>>>   	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> @@ -3236,7 +3255,10 @@ static void gen6_disable_rps(struct drm_device *dev)
>>>>   	I915_WRITE(GEN6_RC_CONTROL, 0);
>>>>   	I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
>>>>
>>>> -	gen6_disable_rps_interrupts(dev);
>>>> +	if (IS_BROADWELL(dev))
>>>> +		gen8_disable_rps_interrupts(dev);
>>>> +	else
>>>> +		gen6_disable_rps_interrupts(dev);
>>>>   }
>>>>
>>>>   static void valleyview_disable_rps(struct drm_device *dev)
>>>> @@ -3276,6 +3298,18 @@ int intel_enable_rc6(const struct drm_device *dev)
>>>>   	return INTEL_RC6_ENABLE;
>>>>   }
>>>>
>>>> +static void gen8_enable_rps_interrupts(struct drm_device *dev)
>>>> +{
>>>> +	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> +
>>>> +	spin_lock_irq(&dev_priv->irq_lock);
>>>> +	WARN_ON(dev_priv->rps.pm_iir);
>>>> +	bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>>>> +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
>>>
>>> The order of "unmask first then clear" seems just wrong. The same issues is
>>> already present in the gen6 code however. So this should be fixed in
>>> both places, or if it's like that on purpose it needs a comment.
>>>
>>
>> Well, if you want to fix it, we can do it in a separate patch. Although
>> I don't think I agree. Why does it seem wrong to you?
>
> If you enable before clearing and there's already an IIR bit high the
> interrupt should trigger immediately before you get to clear it. And
> then on a SMP machine the write to clear it would even race with the
> interrupt handler if there's no locking. So the clearing after
> enabling+unmasking is pointless. The normal approach for enabling
> interrupts is to clear first and then enable.
>
> Hmm. Actually here we alreay have the interrupts enabled in IER, so
> if any relevant IIR bit would be high, we should have already gotten
> the interrupt. But since we always clear the IIR after masking the
> interrupts in IMR, we should never have any relevant IIR bit set here.
>
> So looks to me like we can just drop the IIR writes here. They serve no
> purpose other than racing with the interrupt handler if a real interrupt
> happens just after we've unmasked it.

I think we should create a separate patch to fix this issue for both 
gen6 and gen8

>>
>>>> +	spin_unlock_irq(&dev_priv->irq_lock);
>>>> +
>>>
>>> Useless empty line.
>>>
>>
>> If I was in an arguing mood, I would do, but fine.
>>
>>>> +}
>>>> +
>>>>   static void gen6_enable_rps_interrupts(struct drm_device *dev)
>>>>   {
>>>>   	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> @@ -3378,7 +3412,7 @@ static void gen8_enable_rps(struct drm_device *dev)
>>>>
>>>>   	gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8);
>>>>
>>>> -	gen6_enable_rps_interrupts(dev);
>>>> +	gen8_enable_rps_interrupts(dev);
>>>>
>>>>   	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
>>>>   }
>>
>> Thanks for the review.
>>
>> --
>> Ben Widawsky, Intel Open Source Technology Center
>

Thanks for the review.

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

* Re: [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler
  2014-04-16  8:41       ` Ville Syrjälä
  2014-04-18 12:39         ` S, Deepak
@ 2014-04-18 12:40         ` S, Deepak
  1 sibling, 0 replies; 12+ messages in thread
From: S, Deepak @ 2014-04-18 12:40 UTC (permalink / raw)
  To: Ville Syrjälä, Ben Widawsky; +Cc: intel-gfx, Ben Widawsky



On 4/16/2014 2:11 PM, Ville Syrjälä wrote:
> On Tue, Apr 15, 2014 at 07:43:07PM -0700, Ben Widawsky wrote:
>> On Mon, Apr 14, 2014 at 10:55:53PM +0300, Ville Syrjälä wrote:
>>> On Mon, Apr 14, 2014 at 10:41:14PM +0530, deepak.s@intel.com wrote:
>>>> From: Ben Widawsky <benjamin.widawsky@intel.com>
>>>>
>>>> Almost all of it is reusable from the existing code. The primary
>>>> difference is we need to do even less in the interrupt handler, since
>>>> interrupts are not shared in the same way.
>>>>
>>>> The patch is mostly a copy-paste of the existing snb+ code, with updates
>>>> to the relevant parts requiring changes to the interrupt handling. As
>>>> such it /should/ be relatively trivial. It's highly likely that I missed
>>>> some places where I need a gen8 version of the PM interrupts, but it has
>>>> become invisible to me by now.
>>>>
>>>> This patch could probably be split into adding the new functions,
>>>> followed by actually handling the interrupts. Since the code is
>>>> currently disabled (and broken) I think the patch stands better by
>>>> itself.
>>>>
>>>> v2: Move the commit about not touching the ringbuffer interrupt to the
>>>> snb_* function where it belongs (Rodrigo)
>>>>
>>>> v3: Rebased on Paulo's runtime PM changes
>>>>
>>>> v4: Not well validated, but rebase on
>>>> commit 730488b2eddded4497f63f70867b1256cd9e117c
>>>> Author: Paulo Zanoni <paulo.r.zanoni@intel.com>
>>>> Date:   Fri Mar 7 20:12:32 2014 -0300
>>>>
>>>>      drm/i915: kill dev_priv->pm.regsave
>>>>
>>>> v5: Rebased on latest code base. (Deepak)
>>>>
>>>> Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
>>>>
>>>> Conflicts:
>>>> 	drivers/gpu/drm/i915/i915_irq.c
>>>
>>> IIRC Daniel doesn't like these conflict markers. So should be dropped.
>>>
>>
>> I like the conflict markers generally. Daniel can kill it if he likes,
>> but thanks for the input. I've killed it this time around, but I don't
>> plan on it for the future.
>>
>>>> ---
>>>>   drivers/gpu/drm/i915/i915_irq.c  | 81 +++++++++++++++++++++++++++++++++++++---
>>>>   drivers/gpu/drm/i915/i915_reg.h  |  1 +
>>>>   drivers/gpu/drm/i915/intel_drv.h |  3 +-
>>>>   drivers/gpu/drm/i915/intel_pm.c  | 38 ++++++++++++++++++-
>>>>   4 files changed, 115 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
>>>> index 7a4d3ae..96c459a 100644
>>>> --- a/drivers/gpu/drm/i915/i915_irq.c
>>>> +++ b/drivers/gpu/drm/i915/i915_irq.c
>>>> @@ -248,6 +248,50 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
>>>>   	return true;
>>>>   }
>>>>
>>>> +/**
>>>> +  * bdw_update_pm_irq - update GT interrupt 2
>>>> +  * @dev_priv: driver private
>>>> +  * @interrupt_mask: mask of interrupt bits to update
>>>> +  * @enabled_irq_mask: mask of interrupt bits to enable
>>>> +  *
>>>> +  * Copied from the snb function, updated with relevant register offsets
>>>> +  */
>>>> +static void bdw_update_pm_irq(struct drm_i915_private *dev_priv,
>>>> +			      uint32_t interrupt_mask,
>>>> +			      uint32_t enabled_irq_mask)
>>>> +{
>>>> +	uint32_t new_val;
>>>> +
>>>> +	assert_spin_locked(&dev_priv->irq_lock);
>>>> +
>>>> +	if (dev_priv->pm.irqs_disabled) {
>>>> +		WARN(1, "IRQs disabled\n");
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	new_val = dev_priv->pm_irq_mask;
>>>> +	new_val &= ~interrupt_mask;
>>>> +	new_val |= (~enabled_irq_mask & interrupt_mask);
>>>> +
>>>> +	if (new_val != dev_priv->pm_irq_mask) {
>>>> +		dev_priv->pm_irq_mask = new_val;
>>>> +		I915_WRITE(GEN8_GT_IMR(2), I915_READ(GEN8_GT_IMR(2)) |
>>>> +					   dev_priv->pm_irq_mask);
>>>> +		POSTING_READ(GEN8_GT_IMR(2));
>>>> +	}
>>>> +}
>>>> +
>>>> +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
>>>> +{
>>>> +	bdw_update_pm_irq(dev_priv, mask, mask);
>>>> +}
>>>> +
>>>> +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
>>>> +{
>>>> +	bdw_update_pm_irq(dev_priv, mask, 0);
>>>> +}
>>>> +
>>>> +
>>>
>>> Unnecessary empty line.
>>>
>>
>> Got it, thanks.
>>
>>>>   static bool cpt_can_enable_serr_int(struct drm_device *dev)
>>>>   {
>>>>   	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> @@ -1126,13 +1170,17 @@ static void gen6_pm_rps_work(struct work_struct *work)
>>>>   	spin_lock_irq(&dev_priv->irq_lock);
>>>>   	pm_iir = dev_priv->rps.pm_iir;
>>>>   	dev_priv->rps.pm_iir = 0;
>>>> -	/* Make sure not to corrupt PMIMR state used by ringbuffer code */
>>>> -	snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>>>> +	if (IS_BROADWELL(dev_priv->dev))
>>>> +		bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>>>> +	else {
>>>> +		/* Make sure not to corrupt PMIMR state used by ringbuffer */
>>>> +		snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>>>> +		/* Make sure we didn't queue anything we're not going to
>>>> +		 * process. */
>>>> +		WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
>>>> +	}
>>>>   	spin_unlock_irq(&dev_priv->irq_lock);
>>>>
>>>> -	/* Make sure we didn't queue anything we're not going to process. */
>>>> -	WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
>>>
>>> Isn't this WARN equally valid for bdw?
>>>
>>
>> So first, let me just mention, this has moved slightly in my latest
>> version of this patch, but it's still a valid question.
>>
>> The answer is ambiguous actually. The WARN is always valid technically
>> The distinction in BDW (at least for the time being) is that unlike
>> pre-BDW, PM IIR isn't shared. I can add it, but for BDW, at least right
>> now, DRM_ERROR (or BUG) is more appropriate.
>
> I don't see a reason for bdw to be different here. There are other bits
> in the relevant IIR registers, so the same WARN should be fine.
>
>>
>>
>>>> -
>>>>   	if ((pm_iir & dev_priv->pm_rps_events) == 0)
>>>>   		return;
>>>>
>>>> @@ -1324,6 +1372,19 @@ static void snb_gt_irq_handler(struct drm_device *dev,
>>>>   		ivybridge_parity_error_irq_handler(dev, gt_iir);
>>>>   }
>>>>
>>>> +static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
>>>> +{
>>>> +	if ((pm_iir & dev_priv->pm_rps_events) == 0)
>>>> +		return;
>>>> +
>>>> +	spin_lock(&dev_priv->irq_lock);
>>>> +	dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
>>>> +	bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
>>>> +	spin_unlock(&dev_priv->irq_lock);
>>>> +
>>>> +	queue_work(dev_priv->wq, &dev_priv->rps.work);
>>>> +}
>>>> +
>>>>   static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>>>>   				       struct drm_i915_private *dev_priv,
>>>>   				       u32 master_ctl)
>>>> @@ -1359,6 +1420,16 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>>>>   			DRM_ERROR("The master control interrupt lied (GT1)!\n");
>>>>   	}
>>>>
>>>> +	if (master_ctl & GEN8_GT_PM_IRQ) {
>>>> +		tmp = I915_READ(GEN8_GT_IIR(2));
>>>> +		if (tmp & dev_priv->pm_rps_events) {
>>>> +			ret = IRQ_HANDLED;
>>>> +			gen8_rps_irq_handler(dev_priv, tmp);
>>>> +			I915_WRITE(GEN8_GT_IIR(1), tmp & dev_priv->pm_rps_events);
>>>                                     ^^^^^^^^^^^^^^
>>>
>>> GEN8_GT_IIR(2)
>>>
>>
>> Nice catch, I guess I need to retest after this one.
>
> I'm actually wondering how/if you managed to test this before Deepak's
> PMINTRMSK interrupt redirect bit fix. W/o that you shouldn't be
> getting any interrupt AFAICS.
>
>>
>>>> +		} else
>>>> +			DRM_ERROR("The master control interrupt lied (PM)!\n");
>>>> +	}
>>>> +
>>>>   	if (master_ctl & GEN8_GT_VECS_IRQ) {
>>>>   		tmp = I915_READ(GEN8_GT_IIR(3));
>>>>   		if (tmp) {
>>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>>>> index 8f84555..c2dd436 100644
>>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>>> @@ -4193,6 +4193,7 @@ enum punit_power_well {
>>>>   #define  GEN8_DE_PIPE_A_IRQ		(1<<16)
>>>>   #define  GEN8_DE_PIPE_IRQ(pipe)		(1<<(16+pipe))
>>>>   #define  GEN8_GT_VECS_IRQ		(1<<6)
>>>> +#define  GEN8_GT_PM_IRQ			(1<<4)
>>>>   #define  GEN8_GT_VCS2_IRQ		(1<<3)
>>>>   #define  GEN8_GT_VCS1_IRQ		(1<<2)
>>>>   #define  GEN8_GT_BCS_IRQ		(1<<1)
>>>> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>>>> index c551472..68a078c 100644
>>>> --- a/drivers/gpu/drm/i915/intel_drv.h
>>>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>>>> @@ -650,10 +650,11 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>>   void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>>   void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>>   void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>> +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>> +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>>>>   void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
>>>>   void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
>>>>
>>>> -
>>>
>>> Unrelated whitespace change. IIRC someone left these two empty lines
>>> here on purpose.
>>>
>>
>> Got it, thanks.
>>
>>>>   /* intel_crt.c */
>>>>   void intel_crt_init(struct drm_device *dev);
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
>>>> index 75c1c76..27b64ab 100644
>>>> --- a/drivers/gpu/drm/i915/intel_pm.c
>>>> +++ b/drivers/gpu/drm/i915/intel_pm.c
>>>> @@ -3210,6 +3210,25 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
>>>>   	trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
>>>>   }
>>>>
>>>> +static void gen8_disable_rps_interrupts(struct drm_device *dev)
>>>> +{
>>>> +	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> +
>>>> +	I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
>>>> +	I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
>>>> +				   ~dev_priv->pm_rps_events);
>>>> +	/* 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. */
>>>
>>> This comment would need a bit of update for gen8.
>>>
>>
>> I've killed this comment locally. Somewhere I had written that we can
>> rewrite some of this for gen8, but I seem to have lost that in the sands
>> of time.
>>
>>>> +
>>>> +	spin_lock_irq(&dev_priv->irq_lock);
>>>> +	dev_priv->rps.pm_iir = 0;
>>>> +	spin_unlock_irq(&dev_priv->irq_lock);
>>>> +
>>>> +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
>>>> +}
>>>> +
>>>>   static void gen6_disable_rps_interrupts(struct drm_device *dev)
>>>>   {
>>>>   	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> @@ -3236,7 +3255,10 @@ static void gen6_disable_rps(struct drm_device *dev)
>>>>   	I915_WRITE(GEN6_RC_CONTROL, 0);
>>>>   	I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
>>>>
>>>> -	gen6_disable_rps_interrupts(dev);
>>>> +	if (IS_BROADWELL(dev))
>>>> +		gen8_disable_rps_interrupts(dev);
>>>> +	else
>>>> +		gen6_disable_rps_interrupts(dev);
>>>>   }
>>>>
>>>>   static void valleyview_disable_rps(struct drm_device *dev)
>>>> @@ -3276,6 +3298,18 @@ int intel_enable_rc6(const struct drm_device *dev)
>>>>   	return INTEL_RC6_ENABLE;
>>>>   }
>>>>
>>>> +static void gen8_enable_rps_interrupts(struct drm_device *dev)
>>>> +{
>>>> +	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> +
>>>> +	spin_lock_irq(&dev_priv->irq_lock);
>>>> +	WARN_ON(dev_priv->rps.pm_iir);
>>>> +	bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>>>> +	I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
>>>
>>> The order of "unmask first then clear" seems just wrong. The same issues is
>>> already present in the gen6 code however. So this should be fixed in
>>> both places, or if it's like that on purpose it needs a comment.
>>>
>>
>> Well, if you want to fix it, we can do it in a separate patch. Although
>> I don't think I agree. Why does it seem wrong to you?
>
> If you enable before clearing and there's already an IIR bit high the
> interrupt should trigger immediately before you get to clear it. And
> then on a SMP machine the write to clear it would even race with the
> interrupt handler if there's no locking. So the clearing after
> enabling+unmasking is pointless. The normal approach for enabling
> interrupts is to clear first and then enable.
>
> Hmm. Actually here we alreay have the interrupts enabled in IER, so
> if any relevant IIR bit would be high, we should have already gotten
> the interrupt. But since we always clear the IIR after masking the
> interrupts in IMR, we should never have any relevant IIR bit set here.
>
> So looks to me like we can just drop the IIR writes here. They serve no
> purpose other than racing with the interrupt handler if a real interrupt
> happens just after we've unmasked it.

I think we should create a separate patch to fix this issue for both 
gen6 and gen8

>>
>>>> +	spin_unlock_irq(&dev_priv->irq_lock);
>>>> +
>>>
>>> Useless empty line.
>>>
>>
>> If I was in an arguing mood, I would do, but fine.
>>
>>>> +}
>>>> +
>>>>   static void gen6_enable_rps_interrupts(struct drm_device *dev)
>>>>   {
>>>>   	struct drm_i915_private *dev_priv = dev->dev_private;
>>>> @@ -3378,7 +3412,7 @@ static void gen8_enable_rps(struct drm_device *dev)
>>>>
>>>>   	gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8);
>>>>
>>>> -	gen6_enable_rps_interrupts(dev);
>>>> +	gen8_enable_rps_interrupts(dev);
>>>>
>>>>   	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
>>>>   }
>>
>> Thanks for the review.
>>
>> --
>> Ben Widawsky, Intel Open Source Technology Center
>

Thanks for the review.

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

end of thread, other threads:[~2014-04-18 12:40 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-14 17:11 [PATCH 0/2] Enable PM Interrupts for BDW deepak.s
2014-04-14 17:11 ` [PATCH 1/2] drm/i915/bdw: Implement a basic PM interrupt handler deepak.s
2014-04-14 19:55   ` Ville Syrjälä
2014-04-16  2:43     ` Ben Widawsky
2014-04-16  7:47       ` Daniel Vetter
2014-04-16  8:41       ` Ville Syrjälä
2014-04-18 12:39         ` S, Deepak
2014-04-18 12:40         ` S, Deepak
2014-04-14 17:11 ` [PATCH 2/2] drm/i915: Enable PM Interrupts target via Display Interface deepak.s
2014-04-14 19:36   ` Ville Syrjälä
2014-04-16 13:32     ` Ville Syrjälä
2014-04-18  8:20       ` Deepak S

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.