Skip to content

Commit

Permalink
drm: idiot-proof vblank
Browse files Browse the repository at this point in the history
After spending slightly more time than I'd care to admit debugging the
various and presumably spectacular way things fail when you pass too low
a value to drm_vblank_init() (thanks console-lock for not letting me see
the carnage!), I decided it might be a good idea to add some sanity
checking.

Signed-off-by: Rob Clark <robdclark@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Rob Clark authored and Daniel Vetter committed Aug 6, 2014
1 parent ddde437 commit e6ae868
Showing 1 changed file with 24 additions and 0 deletions.
24 changes: 24 additions & 0 deletions drivers/gpu/drm/drm_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,8 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp);
*/
u32 drm_vblank_count(struct drm_device *dev, int crtc)
{
if (WARN_ON(crtc >= dev->num_crtcs))
return 0;
return atomic_read(&dev->vblank[crtc].count);
}
EXPORT_SYMBOL(drm_vblank_count);
Expand All @@ -752,6 +754,9 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
{
u32 cur_vblank;

if (WARN_ON(crtc >= dev->num_crtcs))
return 0;

/* Read timestamp from slot of _vblank_time ringbuffer
* that corresponds to current vblank count. Retry if
* count has incremented during readout. This works like
Expand Down Expand Up @@ -927,6 +932,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
unsigned long irqflags;
int ret = 0;

if (WARN_ON(crtc >= dev->num_crtcs))
return -EINVAL;

spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Going from 0->1 means we have to enable interrupts again */
if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
Expand Down Expand Up @@ -975,6 +983,9 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
{
BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0);

if (WARN_ON(crtc >= dev->num_crtcs))
return;

/* Last user schedules interrupt disable */
if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
(drm_vblank_offdelay > 0))
Expand Down Expand Up @@ -1019,6 +1030,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
unsigned long irqflags;
unsigned int seq;

if (WARN_ON(crtc >= dev->num_crtcs))
return;

spin_lock_irqsave(&dev->vbl_lock, irqflags);
vblank_disable_and_save(dev, crtc);
wake_up(&dev->vblank[crtc].queue);
Expand Down Expand Up @@ -1078,6 +1092,9 @@ void drm_vblank_on(struct drm_device *dev, int crtc)
{
unsigned long irqflags;

if (WARN_ON(crtc >= dev->num_crtcs))
return;

spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* re-enable interrupts if there's are users left */
if (atomic_read(&dev->vblank[crtc].refcount) != 0)
Expand Down Expand Up @@ -1131,6 +1148,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
/* vblank is not initialized (IRQ not installed ?), or has been freed */
if (!dev->num_crtcs)
return;

if (WARN_ON(crtc >= dev->num_crtcs))
return;

/*
* To avoid all the problems that might happen if interrupts
* were enabled/disabled around or between these calls, we just
Expand Down Expand Up @@ -1439,6 +1460,9 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
if (!dev->num_crtcs)
return false;

if (WARN_ON(crtc >= dev->num_crtcs))
return false;

/* Need timestamp lock to prevent concurrent execution with
* vblank enable/disable, as this would cause inconsistent
* or corrupted timestamps and vblank counts.
Expand Down

0 comments on commit e6ae868

Please sign in to comment.