[PATCH 1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock

Chris Wilson chris at chris-wilson.co.uk
Fri Mar 17 10:19:51 UTC 2017


On Fri, Mar 17, 2017 at 11:47:51AM +0200, Ville Syrjälä wrote:
> On Thu, Mar 16, 2017 at 11:47:48PM +0000, Chris Wilson wrote:
> > @@ -360,7 +358,7 @@ static void vblank_disable_fn(unsigned long arg)
> >  	unsigned long irqflags;
> >  
> >  	spin_lock_irqsave(&dev->vbl_lock, irqflags);
> > -	if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) {
> > +	if (atomic_read(&vblank->refcount) == 0 && READ_ONCE(vblank->enabled)) {
> 
> Hmm. Aren't most of these accesses inside the lock? Looks like you're
> marking everything READ/WRITE_ONCE()?

There's like 3 different locks here. Afaict, the correct one for
serialising vblank->enabled was dev->vblank_time_lock. Every access
outside of that lock, I marked up as READ_ONCE.

Oh, you are using vbl_lock as the barrier? That's not as clear for
disable:

diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 53a526c7b24d..f447ed07ef95 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -325,6 +325,8 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
        struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        unsigned long irqflags;
 
+       assert_spin_locked(&dev->vbl_lock);
+
        /* Prevent vblank irq processing while disabling vblank irqs,
         * so no updates of timestamps or count can happen after we've
         * disabled. Needed to prevent races in case of delayed irq's.


> > @@ -1714,6 +1717,9 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe)
> >  	if (WARN_ON(pipe >= dev->num_crtcs))
> >  		return false;
> >  
> > +	if (!READ_ONCE(vblank->enabled))
> > +		return false;
> 
> This to me looks like it could theoretically cause us to
> miss an interrupt.
> 
> 1. enable_irq()
> 2. drm_update_vblank_count()
> 3. irq fires
> 4. drm_handle_vblank() doesn't do anything
> 5. enabled=true

Sure. There's a danger you miss the irq anyway, and so the last action
after enabling the interrupt should be to process any completed events -
that's implicitly handled by enabling the interrupt in advance of adding
the first event. In the scenario above, there should be nothing to do.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre


More information about the dri-devel mailing list