summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drmP.h1
-rw-r--r--linux-core/drm_irq.c17
2 files changed, 16 insertions, 2 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index cf1c0fd7..0ab69feb 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -832,6 +832,7 @@ typedef struct drm_device {
/* for wraparound handling */
u32 *vblank_offset; /* used to track how many vblanks */
u32 *vblank_premodeset; /* were lost during modeset */
+ struct timer_list vblank_disable_timer;
unsigned long max_vblank_count; /**< size of vblank counter register */
spinlock_t tasklet_lock; /**< For drm_locked_tasklet */
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index c9d1c0d2..1e1b7f4d 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -77,10 +77,22 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp,
return 0;
}
+static void vblank_disable_fn(unsigned long arg)
+{
+ drm_device_t *dev = (drm_device_t *)arg;
+ int i;
+
+ for (i = 0; i < dev->num_crtcs; i++)
+ if (atomic_read(&dev->vblank_refcount[i]) == 0)
+ dev->driver->disable_vblank(dev, i);
+}
+
int drm_vblank_init(drm_device_t *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);
atomic_set(&dev->vbl_signal_pending, 0);
dev->num_crtcs = num_crtcs;
@@ -377,9 +389,10 @@ EXPORT_SYMBOL(drm_vblank_get);
*/
void drm_vblank_put(drm_device_t *dev, int crtc)
{
- /* Last user can disable interrupts */
+ /* Last user schedules interrupt disable */
if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
- dev->driver->disable_vblank(dev, crtc);
+ mod_timer(&dev->vblank_disable_timer,
+ round_jiffies_relative(DRM_HZ));
}
EXPORT_SYMBOL(drm_vblank_put);