[Intel-gfx] [PATCH] drm/i915: Drop pipe_enable checks in vblank funcs

Daniel Vetter daniel at ffwll.ch
Wed Jan 28 01:33:30 PST 2015


On Mon, Jan 26, 2015 at 11:03:14PM +0200, Laurent Pinchart wrote:
> Hi Daniel,
> 
> Thank you for the patch.
> 
> On Monday 26 January 2015 07:41:59 Daniel Vetter wrote:
> > With Ville's rework to use drm_crtc_vblank_on/off the core will take
> > care of rejecting drm_vblank_get calls when the pipe is off.
> 
> After debugging a related issue in the omapdrm driver I think this is only 
> partially true. drm_vblank_off() will increase the vblank refcount, resulting 
> in drm_vblank_get() returning an error instead of calling the driver's 
> .enable_vblank operation. However, this only works if drm_vblank_off() has 
> been called, not when the pipe is off because it hasn't been turned on yet.

We recover this state at driver load by manually calling off/on. See intel_sanitize_crtc

> Consider this case. The driver has just been loaded, all pipes are off. An 
> application opens the DRM device node and closes it without enabling the pipe. 
> The lastclose operation will be called, and it will call 
> drm_fb_helper_restore_fbdev_mode_unlocked() to restore the CRTC. This triggers 
> the timeout warning in drm_wait_one_vblank with omapdrm when using the atomic 
> update transitional helpers. The callstack is as follows.
> 
> [<bf3b46f8>] (drm_wait_one_vblank [drm])
> [<bf429e50>] (drm_plane_helper_commit [drm_kms_helper])
> [<bf427ab0>] (drm_crtc_helper_set_mode [drm_kms_helper])
> [<bf428570>] (drm_crtc_helper_set_config [drm_kms_helper])
> [<bf3baa34>] (drm_mode_set_config_internal [drm])
> [<bf431374>] (restore_fbdev_mode [drm_kms_helper])
> [<bf432978>] (drm_fb_helper_restore_fbdev_mode_unlocked [drm_kms_helper])
> [<bf45d4f4>] (dev_lastclose [omapdrm])
> [<bf3b1218>] (drm_lastclose [drm])
> [<bf3b15e0>] (drm_release [drm])
> [<c0149104>] (__fput)
> [<c00571d4>] (task_work_run)
> [<c00114f8>] (do_work_pending)
> 
> The drm_crtc_vblank_get() call in drm_plane_helper_commit() will not return an 
> error as drm_vblank_off() has never been called so far.
> 
> The exact same issue obviously doesn't affect the i915 driver as it doesn't 
> use the transitional helpers, but a different issue could be present with the 
> same root cause.

We use the transitional helpers, code will land in drm-next soonish.

> Where do you think this should be fixed ?

Proper hw state readout for smooth booting is hard. I've tried to aim a
bit in that direction with the ->reset callbacks for atomic, but maybe we
should do a new helper inspired by i915 just for this kind of stuff ...

My idea would be to add ->read_hw_state hooks which will out the various
drm_*_state structs and then use that for both ->reset and for
cross-checking after modesets. And then we could shovel a bunch of the
common code to sanitize hw state into the shared ->reset functions.
But given that no one else but i915 tries really hard to reconstruct hw
state probably not yet worth it.
-Daniel

> 
> > Also the core won't call the get_vblank_counter hooks in that case either.
> > And since we've dropped ums support recently we can now remove these
> > hacks, yay!
> > 
> > Noticed while trying to answer questions Laurent had about how the new
> > atomic helpers work.
> >
> > Cc: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > Signed-off-by: Daniel Vetter <daniel.vetter at intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_irq.c | 52 --------------------------------------
> >  1 file changed, 52 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c
> > b/drivers/gpu/drm/i915/i915_irq.c index 2399eaed2ca3..4761f7fe6fb1 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -492,31 +492,6 @@ static void i915_enable_asle_pipestat(struct drm_device
> > *dev) spin_unlock_irq(&dev_priv->irq_lock);
> >  }
> > 
> > -/**
> > - * i915_pipe_enabled - check if a pipe is enabled
> > - * @dev: DRM device
> > - * @pipe: pipe to check
> > - *
> > - * Reading certain registers when the pipe is disabled can hang the chip.
> > - * Use this routine to make sure the PLL is running and the pipe is active
> > - * before reading such registers if unsure.
> > - */
> > -static int
> > -i915_pipe_enabled(struct drm_device *dev, int pipe)
> > -{
> > -	struct drm_i915_private *dev_priv = dev->dev_private;
> > -
> > -	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
> > -		/* Locking is horribly broken here, but whatever. */
> > -		struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
> > -		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > -
> > -		return intel_crtc->active;
> > -	} else {
> > -		return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
> > -	}
> > -}
> > -
> >  /*
> >   * This timing diagram depicts the video signal in and
> >   * around the vertical blanking period.
> > @@ -583,12 +558,6 @@ static u32 i915_get_vblank_counter(struct drm_device
> > *dev, int pipe) unsigned long low_frame;
> >  	u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
> > 
> > -	if (!i915_pipe_enabled(dev, pipe)) {
> > -		DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
> > -				"pipe %c\n", pipe_name(pipe));
> > -		return 0;
> > -	}
> > -
> >  	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
> >  		struct intel_crtc *intel_crtc =
> >  			to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> > @@ -648,12 +617,6 @@ static u32 gm45_get_vblank_counter(struct drm_device
> > *dev, int pipe) struct drm_i915_private *dev_priv = dev->dev_private;
> >  	int reg = PIPE_FRMCOUNT_GM45(pipe);
> > 
> > -	if (!i915_pipe_enabled(dev, pipe)) {
> > -		DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
> > -				 "pipe %c\n", pipe_name(pipe));
> > -		return 0;
> > -	}
> > -
> >  	return I915_READ(reg);
> >  }
> > 
> > @@ -2660,9 +2623,6 @@ static int i915_enable_vblank(struct drm_device *dev,
> > int pipe) struct drm_i915_private *dev_priv = dev->dev_private;
> >  	unsigned long irqflags;
> > 
> > -	if (!i915_pipe_enabled(dev, pipe))
> > -		return -EINVAL;
> > -
> >  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> >  	if (INTEL_INFO(dev)->gen >= 4)
> >  		i915_enable_pipestat(dev_priv, pipe,
> > @@ -2682,9 +2642,6 @@ static int ironlake_enable_vblank(struct drm_device
> > *dev, int pipe) uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ?
> > DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe);
> > 
> > -	if (!i915_pipe_enabled(dev, pipe))
> > -		return -EINVAL;
> > -
> >  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> >  	ironlake_enable_display_irq(dev_priv, bit);
> >  	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> > @@ -2697,9 +2654,6 @@ static int valleyview_enable_vblank(struct drm_device
> > *dev, int pipe) struct drm_i915_private *dev_priv = dev->dev_private;
> >  	unsigned long irqflags;
> > 
> > -	if (!i915_pipe_enabled(dev, pipe))
> > -		return -EINVAL;
> > -
> >  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> >  	i915_enable_pipestat(dev_priv, pipe,
> >  			     PIPE_START_VBLANK_INTERRUPT_STATUS);
> > @@ -2713,9 +2667,6 @@ static int gen8_enable_vblank(struct drm_device *dev,
> > int pipe) struct drm_i915_private *dev_priv = dev->dev_private;
> >  	unsigned long irqflags;
> > 
> > -	if (!i915_pipe_enabled(dev, pipe))
> > -		return -EINVAL;
> > -
> >  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> >  	dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_VBLANK;
> >  	I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
> > @@ -2767,9 +2718,6 @@ static void gen8_disable_vblank(struct drm_device
> > *dev, int pipe) struct drm_i915_private *dev_priv = dev->dev_private;
> >  	unsigned long irqflags;
> > 
> > -	if (!i915_pipe_enabled(dev, pipe))
> > -		return;
> > -
> >  	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> >  	dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_VBLANK;
> >  	I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

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


More information about the Intel-gfx mailing list