aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_irq.c
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2009-09-11 14:33:34 -0400
committerDave Airlie <airlied@redhat.com>2009-11-17 19:02:47 -0500
commitc9a9c5e02aedc1a2815877b0268f886d2640b771 (patch)
tree51f69f2ec6dcebb019cd6aa22b9e29ee48c397c1 /drivers/gpu/drm/drm_irq.c
parent799dd75b1a8380a967c929a4551895788c374b31 (diff)
drm: Add async event synchronization for drmWaitVblank
This patch adds a new flag to the drmWaitVblank ioctl, which asks the drm to return immediately and notify userspace when the specified vblank sequence happens by sending an event back on the drm fd. The event mechanism works with the other flags supported by the ioctls, specifically, the vblank sequence can be specified relatively or absolutely, and works for primary and seconday crtc. The signal field of the vblank request is used to provide user data, which will be sent back to user space in the vblank event. Signed-off-by: Kristian Høgsberg <krh@redhat.com> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r--drivers/gpu/drm/drm_irq.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 0a6f0b3bdc78..72754aca7abf 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -550,6 +550,62 @@ out:
550 return ret; 550 return ret;
551} 551}
552 552
553static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
554 union drm_wait_vblank *vblwait,
555 struct drm_file *file_priv)
556{
557 struct drm_pending_vblank_event *e;
558 struct timeval now;
559 unsigned long flags;
560 unsigned int seq;
561
562 e = kzalloc(sizeof *e, GFP_KERNEL);
563 if (e == NULL)
564 return -ENOMEM;
565
566 e->pipe = pipe;
567 e->event.base.type = DRM_EVENT_VBLANK;
568 e->event.base.length = sizeof e->event;
569 e->event.user_data = vblwait->request.signal;
570 e->base.event = &e->event.base;
571 e->base.file_priv = file_priv;
572 e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
573
574 do_gettimeofday(&now);
575 spin_lock_irqsave(&dev->event_lock, flags);
576
577 if (file_priv->event_space < sizeof e->event) {
578 spin_unlock_irqrestore(&dev->event_lock, flags);
579 kfree(e);
580 return -ENOMEM;
581 }
582
583 file_priv->event_space -= sizeof e->event;
584 seq = drm_vblank_count(dev, pipe);
585 if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
586 (seq - vblwait->request.sequence) <= (1 << 23)) {
587 vblwait->request.sequence = seq + 1;
588 }
589
590 DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
591 vblwait->request.sequence, seq, pipe);
592
593 e->event.sequence = vblwait->request.sequence;
594 if ((seq - vblwait->request.sequence) <= (1 << 23)) {
595 e->event.tv_sec = now.tv_sec;
596 e->event.tv_usec = now.tv_usec;
597 drm_vblank_put(dev, e->pipe);
598 list_add_tail(&e->base.link, &e->base.file_priv->event_list);
599 wake_up_interruptible(&e->base.file_priv->event_wait);
600 } else {
601 list_add_tail(&e->base.link, &dev->vblank_event_list);
602 }
603
604 spin_unlock_irqrestore(&dev->event_lock, flags);
605
606 return 0;
607}
608
553/** 609/**
554 * Wait for VBLANK. 610 * Wait for VBLANK.
555 * 611 *
@@ -609,6 +665,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
609 goto done; 665 goto done;
610 } 666 }
611 667
668 if (flags & _DRM_VBLANK_EVENT)
669 return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);
670
612 if ((flags & _DRM_VBLANK_NEXTONMISS) && 671 if ((flags & _DRM_VBLANK_NEXTONMISS) &&
613 (seq - vblwait->request.sequence) <= (1<<23)) { 672 (seq - vblwait->request.sequence) <= (1<<23)) {
614 vblwait->request.sequence = seq + 1; 673 vblwait->request.sequence = seq + 1;
@@ -641,6 +700,38 @@ done:
641 return ret; 700 return ret;
642} 701}
643 702
703void drm_handle_vblank_events(struct drm_device *dev, int crtc)
704{
705 struct drm_pending_vblank_event *e, *t;
706 struct timeval now;
707 unsigned long flags;
708 unsigned int seq;
709
710 do_gettimeofday(&now);
711 seq = drm_vblank_count(dev, crtc);
712
713 spin_lock_irqsave(&dev->event_lock, flags);
714
715 list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
716 if (e->pipe != crtc)
717 continue;
718 if ((seq - e->event.sequence) > (1<<23))
719 continue;
720
721 DRM_DEBUG("vblank event on %d, current %d\n",
722 e->event.sequence, seq);
723
724 e->event.sequence = seq;
725 e->event.tv_sec = now.tv_sec;
726 e->event.tv_usec = now.tv_usec;
727 drm_vblank_put(dev, e->pipe);
728 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
729 wake_up_interruptible(&e->base.file_priv->event_wait);
730 }
731
732 spin_unlock_irqrestore(&dev->event_lock, flags);
733}
734
644/** 735/**
645 * drm_handle_vblank - handle a vblank event 736 * drm_handle_vblank - handle a vblank event
646 * @dev: DRM device 737 * @dev: DRM device
@@ -651,7 +742,11 @@ done:
651 */ 742 */
652void drm_handle_vblank(struct drm_device *dev, int crtc) 743void drm_handle_vblank(struct drm_device *dev, int crtc)
653{ 744{
745 if (!dev->num_crtcs)
746 return;
747
654 atomic_inc(&dev->_vblank_count[crtc]); 748 atomic_inc(&dev->_vblank_count[crtc]);
655 DRM_WAKEUP(&dev->vbl_queue[crtc]); 749 DRM_WAKEUP(&dev->vbl_queue[crtc]);
750 drm_handle_vblank_events(dev, crtc);
656} 751}
657EXPORT_SYMBOL(drm_handle_vblank); 752EXPORT_SYMBOL(drm_handle_vblank);