summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_irq.c
diff options
context:
space:
mode:
authorVille Syrjälä2014-02-19 18:36:08 +0100
committerDaniel Vetter2014-05-20 21:13:33 +0200
commite69595c2501094d85d5bbca87592acb8a481109a (patch)
treee7b3910270104711cab832ab2aae4f8a0b696ed8 /drivers/gpu/drm/drm_irq.c
parentdrm: Use correct spinlock flavor in drm_vblank_get() (diff)
downloadkernel-qcow2-linux-e69595c2501094d85d5bbca87592acb8a481109a.tar.gz
kernel-qcow2-linux-e69595c2501094d85d5bbca87592acb8a481109a.tar.xz
kernel-qcow2-linux-e69595c2501094d85d5bbca87592acb8a481109a.zip
drm: Make the vblank disable timer per-crtc
Currently there's one per-device vblank disable timer, and it gets reset wheneven the vblank refcount for any crtc drops to zero. That means that one crtc could accidentally be keeping the vblank interrupts for other crtcs enabled even if there are no users for them. Make the disable timer per-crtc to avoid this issue. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r--drivers/gpu/drm/drm_irq.c40
1 files changed, 21 insertions, 19 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index ea20c4aa1b6b..90c59a8c820f 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -140,33 +140,34 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
static void vblank_disable_fn(unsigned long arg)
{
- struct drm_device *dev = (struct drm_device *)arg;
+ struct drm_vblank_crtc *vblank = (void *)arg;
+ struct drm_device *dev = vblank->dev;
unsigned long irqflags;
- int i;
+ int crtc = vblank->crtc;
if (!dev->vblank_disable_allowed)
return;
- for (i = 0; i < dev->num_crtcs; i++) {
- spin_lock_irqsave(&dev->vbl_lock, irqflags);
- if (atomic_read(&dev->vblank[i].refcount) == 0 &&
- dev->vblank[i].enabled) {
- DRM_DEBUG("disabling vblank on crtc %d\n", i);
- vblank_disable_and_save(dev, i);
- }
- spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) {
+ DRM_DEBUG("disabling vblank on crtc %d\n", crtc);
+ vblank_disable_and_save(dev, crtc);
}
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
void drm_vblank_cleanup(struct drm_device *dev)
{
+ int crtc;
+
/* Bail if the driver didn't call drm_vblank_init() */
if (dev->num_crtcs == 0)
return;
- del_timer_sync(&dev->vblank_disable_timer);
-
- vblank_disable_fn((unsigned long)dev);
+ for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
+ del_timer_sync(&dev->vblank[crtc].disable_timer);
+ vblank_disable_fn((unsigned long)&dev->vblank[crtc]);
+ }
kfree(dev->vblank);
@@ -178,8 +179,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
{
int i, ret = -ENOMEM;
- setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
- (unsigned long)dev);
spin_lock_init(&dev->vbl_lock);
spin_lock_init(&dev->vblank_time_lock);
@@ -189,8 +188,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
if (!dev->vblank)
goto err;
- for (i = 0; i < num_crtcs; i++)
+ for (i = 0; i < num_crtcs; i++) {
+ dev->vblank[i].dev = dev;
+ dev->vblank[i].crtc = i;
init_waitqueue_head(&dev->vblank[i].queue);
+ setup_timer(&dev->vblank[i].disable_timer, vblank_disable_fn,
+ (unsigned long)&dev->vblank[i]);
+ }
DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n");
@@ -900,7 +904,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
/* Last user schedules interrupt disable */
if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
(drm_vblank_offdelay > 0))
- mod_timer(&dev->vblank_disable_timer,
+ mod_timer(&dev->vblank[crtc].disable_timer,
jiffies + ((drm_vblank_offdelay * HZ)/1000));
}
EXPORT_SYMBOL(drm_vblank_put);
@@ -909,8 +913,6 @@ EXPORT_SYMBOL(drm_vblank_put);
* drm_vblank_off - disable vblank events on a CRTC
* @dev: DRM device
* @crtc: CRTC in question
- *
- * Caller must hold event lock.
*/
void drm_vblank_off(struct drm_device *dev, int crtc)
{