diff mbox

drm/i915: Grab RPM wakeref around enabling vblank interrupts

Message ID 20161007135032.12825-1-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson Oct. 7, 2016, 1:50 p.m. UTC
Whilst the vblank is configured to send an interrupt everytime, we need
to keep the device awake to process those interrupts.

Reported-by: Anssi Hannula <anssi.hannula@bitwise.fi>
References: https://bugs.freedesktop.org/show_bug.cgi?id=97985
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Comments

Ville Syrjala Oct. 7, 2016, 6:06 p.m. UTC | #1
On Fri, Oct 07, 2016 at 02:50:32PM +0100, Chris Wilson wrote:
> Whilst the vblank is configured to send an interrupt everytime, we need
> to keep the device awake to process those interrupts.

If we can enable vblanks the pipe will be active, and thus we can't
runtime suspend anyway. Also might_sleep() would be a problem.

> 
> Reported-by: Anssi Hannula <anssi.hannula@bitwise.fi>
> References: https://bugs.freedesktop.org/show_bug.cgi?id=97985
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index bd6c8b0eeaef..bda7a27615a6 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2723,6 +2723,8 @@ static int i915_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	unsigned long irqflags;
>  
> +	intel_runtime_pm_get(dev_priv);
> +
>  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>  	if (INTEL_INFO(dev)->gen >= 4)
>  		i915_enable_pipestat(dev_priv, pipe,
> @@ -2742,6 +2744,8 @@ static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  	uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
>  						     DE_PIPE_VBLANK(pipe);
>  
> +	intel_runtime_pm_get(dev_priv);
> +
>  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>  	ilk_enable_display_irq(dev_priv, bit);
>  	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> @@ -2754,6 +2758,8 @@ static int valleyview_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	unsigned long irqflags;
>  
> +	intel_runtime_pm_get(dev_priv);
> +
>  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>  	i915_enable_pipestat(dev_priv, pipe,
>  			     PIPE_START_VBLANK_INTERRUPT_STATUS);
> @@ -2767,6 +2773,8 @@ static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	unsigned long irqflags;
>  
> +	intel_runtime_pm_get(dev_priv);
> +
>  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>  	bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
>  	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> @@ -2787,6 +2795,8 @@ static void i915_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  			      PIPE_VBLANK_INTERRUPT_STATUS |
>  			      PIPE_START_VBLANK_INTERRUPT_STATUS);
>  	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +
> +	intel_runtime_pm_put(dev_priv);
>  }
>  
>  static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe)
> @@ -2799,6 +2809,8 @@ static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>  	ilk_disable_display_irq(dev_priv, bit);
>  	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +
> +	intel_runtime_pm_put(dev_priv);
>  }
>  
>  static void valleyview_disable_vblank(struct drm_device *dev, unsigned int pipe)
> @@ -2810,6 +2822,8 @@ static void valleyview_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  	i915_disable_pipestat(dev_priv, pipe,
>  			      PIPE_START_VBLANK_INTERRUPT_STATUS);
>  	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +
> +	intel_runtime_pm_put(dev_priv);
>  }
>  
>  static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
> @@ -2820,6 +2834,8 @@ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
>  	bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
>  	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +
> +	intel_runtime_pm_put(dev_priv);
>  }
>  
>  static bool
> -- 
> 2.9.3
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Chris Wilson Oct. 7, 2016, 6:33 p.m. UTC | #2
On Fri, Oct 07, 2016 at 09:06:07PM +0300, Ville Syrjälä wrote:
> On Fri, Oct 07, 2016 at 02:50:32PM +0100, Chris Wilson wrote:
> > Whilst the vblank is configured to send an interrupt everytime, we need
> > to keep the device awake to process those interrupts.
> 
> If we can enable vblanks the pipe will be active, and thus we can't
> runtime suspend anyway. Also might_sleep() would be a problem.

Where is the pipe made active? Is it just having any mode is sufficient
to disable rpm? Will that always be the case?

Just tracing from the drm_wait_vblank ioctl to the mmio access it didn't
occur to me that there was a crtc wakeref.

Choice is either using something like intel_runtime_pm_get_noresume() or
/* CRTC must be kept alive whilst we enable vblanks */
assert_rpm...()

And possibly even using the seq check.
-Chris
Ville Syrjala Oct. 7, 2016, 6:44 p.m. UTC | #3
On Fri, Oct 07, 2016 at 07:33:00PM +0100, Chris Wilson wrote:
> On Fri, Oct 07, 2016 at 09:06:07PM +0300, Ville Syrjälä wrote:
> > On Fri, Oct 07, 2016 at 02:50:32PM +0100, Chris Wilson wrote:
> > > Whilst the vblank is configured to send an interrupt everytime, we need
> > > to keep the device awake to process those interrupts.
> > 
> > If we can enable vblanks the pipe will be active, and thus we can't
> > runtime suspend anyway. Also might_sleep() would be a problem.
> 
> Where is the pipe made active? Is it just having any mode is sufficient
> to disable rpm? Will that always be the case?

Active pipe holds a power domain reference, which implies an rpm
reference as well.

> 
> Just tracing from the drm_wait_vblank ioctl to the mmio access it didn't
> occur to me that there was a crtc wakeref.
> 
> Choice is either using something like intel_runtime_pm_get_noresume() or
> /* CRTC must be kept alive whilst we enable vblanks */
> assert_rpm...()
> 
> And possibly even using the seq check.
> -Chris
> 
> -- 
> Chris Wilson, Intel Open Source Technology Centre
Chris Wilson Oct. 7, 2016, 6:57 p.m. UTC | #4
On Fri, Oct 07, 2016 at 09:44:53PM +0300, Ville Syrjälä wrote:
> On Fri, Oct 07, 2016 at 07:33:00PM +0100, Chris Wilson wrote:
> > On Fri, Oct 07, 2016 at 09:06:07PM +0300, Ville Syrjälä wrote:
> > > On Fri, Oct 07, 2016 at 02:50:32PM +0100, Chris Wilson wrote:
> > > > Whilst the vblank is configured to send an interrupt everytime, we need
> > > > to keep the device awake to process those interrupts.
> > > 
> > > If we can enable vblanks the pipe will be active, and thus we can't
> > > runtime suspend anyway. Also might_sleep() would be a problem.
> > 
> > Where is the pipe made active? Is it just having any mode is sufficient
> > to disable rpm? Will that always be the case?
> 
> Active pipe holds a power domain reference, which implies an rpm
> reference as well.

What's the best way to write

	/* vblank IRQ requires the powerwell to stay awake */
	WARN_ON(!to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe])->active);

?
Chris Wilson Oct. 7, 2016, 7 p.m. UTC | #5
On Fri, Oct 07, 2016 at 07:57:21PM +0100, Chris Wilson wrote:
> On Fri, Oct 07, 2016 at 09:44:53PM +0300, Ville Syrjälä wrote:
> > On Fri, Oct 07, 2016 at 07:33:00PM +0100, Chris Wilson wrote:
> > > On Fri, Oct 07, 2016 at 09:06:07PM +0300, Ville Syrjälä wrote:
> > > > On Fri, Oct 07, 2016 at 02:50:32PM +0100, Chris Wilson wrote:
> > > > > Whilst the vblank is configured to send an interrupt everytime, we need
> > > > > to keep the device awake to process those interrupts.
> > > > 
> > > > If we can enable vblanks the pipe will be active, and thus we can't
> > > > runtime suspend anyway. Also might_sleep() would be a problem.
> > > 
> > > Where is the pipe made active? Is it just having any mode is sufficient
> > > to disable rpm? Will that always be the case?
> > 
> > Active pipe holds a power domain reference, which implies an rpm
> > reference as well.
> 
> What's the best way to write
> 
> 	/* vblank IRQ requires the powerwell to stay awake */
> 	WARN_ON(!to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe])->active);

Also, any reason why we shouldn't merge valleyview_enable_vblank() with
i915_enable_vblank()?
-Chris
Ville Syrjala Oct. 7, 2016, 7:17 p.m. UTC | #6
On Fri, Oct 07, 2016 at 08:00:35PM +0100, Chris Wilson wrote:
> On Fri, Oct 07, 2016 at 07:57:21PM +0100, Chris Wilson wrote:
> > On Fri, Oct 07, 2016 at 09:44:53PM +0300, Ville Syrjälä wrote:
> > > On Fri, Oct 07, 2016 at 07:33:00PM +0100, Chris Wilson wrote:
> > > > On Fri, Oct 07, 2016 at 09:06:07PM +0300, Ville Syrjälä wrote:
> > > > > On Fri, Oct 07, 2016 at 02:50:32PM +0100, Chris Wilson wrote:
> > > > > > Whilst the vblank is configured to send an interrupt everytime, we need
> > > > > > to keep the device awake to process those interrupts.
> > > > > 
> > > > > If we can enable vblanks the pipe will be active, and thus we can't
> > > > > runtime suspend anyway. Also might_sleep() would be a problem.
> > > > 
> > > > Where is the pipe made active? Is it just having any mode is sufficient
> > > > to disable rpm? Will that always be the case?
> > > 
> > > Active pipe holds a power domain reference, which implies an rpm
> > > reference as well.
> > 
> > What's the best way to write
> > 
> > 	/* vblank IRQ requires the powerwell to stay awake */
> > 	WARN_ON(!to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe])->active);

Probably just that. We have some kind of function to hide the details
of the array a bit though, I just never rememer what it's called.
And I think I have patches somewhere to convert all of that over to
storing intel_crtc * instead of drm_crtc * since that's what everyone
wants.

> 
> Also, any reason why we shouldn't merge valleyview_enable_vblank() with
> i915_enable_vblank()?

No reason AFAICS. Same for disable. Though maybe we should add the gen
check to disable to make it symmetric, just to avoid some head scratching.

Hmm. Or actually, maybe just split to i915_*_vblank() and i965_*_vblank()
instead. Not much point in having the if in there when you can just
assign the right function pointer to begin with.
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index bd6c8b0eeaef..bda7a27615a6 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2723,6 +2723,8 @@  static int i915_enable_vblank(struct drm_device *dev, unsigned int pipe)
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	unsigned long irqflags;
 
+	intel_runtime_pm_get(dev_priv);
+
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	if (INTEL_INFO(dev)->gen >= 4)
 		i915_enable_pipestat(dev_priv, pipe,
@@ -2742,6 +2744,8 @@  static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe)
 	uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
 						     DE_PIPE_VBLANK(pipe);
 
+	intel_runtime_pm_get(dev_priv);
+
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	ilk_enable_display_irq(dev_priv, bit);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -2754,6 +2758,8 @@  static int valleyview_enable_vblank(struct drm_device *dev, unsigned int pipe)
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	unsigned long irqflags;
 
+	intel_runtime_pm_get(dev_priv);
+
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, pipe,
 			     PIPE_START_VBLANK_INTERRUPT_STATUS);
@@ -2767,6 +2773,8 @@  static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe)
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	unsigned long irqflags;
 
+	intel_runtime_pm_get(dev_priv);
+
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -2787,6 +2795,8 @@  static void i915_disable_vblank(struct drm_device *dev, unsigned int pipe)
 			      PIPE_VBLANK_INTERRUPT_STATUS |
 			      PIPE_START_VBLANK_INTERRUPT_STATUS);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+	intel_runtime_pm_put(dev_priv);
 }
 
 static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe)
@@ -2799,6 +2809,8 @@  static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	ilk_disable_display_irq(dev_priv, bit);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+	intel_runtime_pm_put(dev_priv);
 }
 
 static void valleyview_disable_vblank(struct drm_device *dev, unsigned int pipe)
@@ -2810,6 +2822,8 @@  static void valleyview_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	i915_disable_pipestat(dev_priv, pipe,
 			      PIPE_START_VBLANK_INTERRUPT_STATUS);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+	intel_runtime_pm_put(dev_priv);
 }
 
 static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
@@ -2820,6 +2834,8 @@  static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+	intel_runtime_pm_put(dev_priv);
 }
 
 static bool