aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r--drivers/gpu/drm/drm_irq.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 0a6f0b3bdc78..6b3ce6d38848 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -550,6 +550,63 @@ 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 vblwait->reply.sequence = vblwait->request.sequence;
589 }
590
591 DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
592 vblwait->request.sequence, seq, pipe);
593
594 e->event.sequence = vblwait->request.sequence;
595 if ((seq - vblwait->request.sequence) <= (1 << 23)) {
596 e->event.tv_sec = now.tv_sec;
597 e->event.tv_usec = now.tv_usec;
598 drm_vblank_put(dev, e->pipe);
599 list_add_tail(&e->base.link, &e->base.file_priv->event_list);
600 wake_up_interruptible(&e->base.file_priv->event_wait);
601 } else {
602 list_add_tail(&e->base.link, &dev->vblank_event_list);
603 }
604
605 spin_unlock_irqrestore(&dev->event_lock, flags);
606
607 return 0;
608}
609
553/** 610/**
554 * Wait for VBLANK. 611 * Wait for VBLANK.
555 * 612 *
@@ -609,6 +666,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
609 goto done; 666 goto done;
610 } 667 }
611 668
669 if (flags & _DRM_VBLANK_EVENT)
670 return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);
671
612 if ((flags & _DRM_VBLANK_NEXTONMISS) && 672 if ((flags & _DRM_VBLANK_NEXTONMISS) &&
613 (seq - vblwait->request.sequence) <= (1<<23)) { 673 (seq - vblwait->request.sequence) <= (1<<23)) {
614 vblwait->request.sequence = seq + 1; 674 vblwait->request.sequence = seq + 1;
@@ -641,6 +701,38 @@ done:
641 return ret; 701 return ret;
642} 702}
643 703
704void drm_handle_vblank_events(struct drm_device *dev, int crtc)
705{
706 struct drm_pending_vblank_event *e, *t;
707 struct timeval now;
708 unsigned long flags;
709 unsigned int seq;
710
711 do_gettimeofday(&now);
712 seq = drm_vblank_count(dev, crtc);
713
714 spin_lock_irqsave(&dev->event_lock, flags);
715
716 list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
717 if (e->pipe != crtc)
718 continue;
719 if ((seq - e->event.sequence) > (1<<23))
720 continue;
721
722 DRM_DEBUG("vblank event on %d, current %d\n",
723 e->event.sequence, seq);
724
725 e->event.sequence = seq;
726 e->event.tv_sec = now.tv_sec;
727 e->event.tv_usec = now.tv_usec;
728 drm_vblank_put(dev, e->pipe);
729 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
730 wake_up_interruptible(&e->base.file_priv->event_wait);
731 }
732
733 spin_unlock_irqrestore(&dev->event_lock, flags);
734}
735
644/** 736/**
645 * drm_handle_vblank - handle a vblank event 737 * drm_handle_vblank - handle a vblank event
646 * @dev: DRM device 738 * @dev: DRM device
@@ -651,7 +743,11 @@ done:
651 */ 743 */
652void drm_handle_vblank(struct drm_device *dev, int crtc) 744void drm_handle_vblank(struct drm_device *dev, int crtc)
653{ 745{
746 if (!dev->num_crtcs)
747 return;
748
654 atomic_inc(&dev->_vblank_count[crtc]); 749 atomic_inc(&dev->_vblank_count[crtc]);
655 DRM_WAKEUP(&dev->vbl_queue[crtc]); 750 DRM_WAKEUP(&dev->vbl_queue[crtc]);
751 drm_handle_vblank_events(dev, crtc);
656} 752}
657EXPORT_SYMBOL(drm_handle_vblank); 753EXPORT_SYMBOL(drm_handle_vblank);