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.c130
1 files changed, 122 insertions, 8 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 0a6f0b3bdc78..7998ee66b317 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -429,15 +429,21 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
429 429
430 spin_lock_irqsave(&dev->vbl_lock, irqflags); 430 spin_lock_irqsave(&dev->vbl_lock, irqflags);
431 /* Going from 0->1 means we have to enable interrupts again */ 431 /* Going from 0->1 means we have to enable interrupts again */
432 if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && 432 if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
433 !dev->vblank_enabled[crtc]) { 433 if (!dev->vblank_enabled[crtc]) {
434 ret = dev->driver->enable_vblank(dev, crtc); 434 ret = dev->driver->enable_vblank(dev, crtc);
435 DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); 435 DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
436 if (ret) 436 if (ret)
437 atomic_dec(&dev->vblank_refcount[crtc]);
438 else {
439 dev->vblank_enabled[crtc] = 1;
440 drm_update_vblank_count(dev, crtc);
441 }
442 }
443 } else {
444 if (!dev->vblank_enabled[crtc]) {
437 atomic_dec(&dev->vblank_refcount[crtc]); 445 atomic_dec(&dev->vblank_refcount[crtc]);
438 else { 446 ret = -EINVAL;
439 dev->vblank_enabled[crtc] = 1;
440 drm_update_vblank_count(dev, crtc);
441 } 447 }
442 } 448 }
443 spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 449 spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
@@ -464,6 +470,18 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
464} 470}
465EXPORT_SYMBOL(drm_vblank_put); 471EXPORT_SYMBOL(drm_vblank_put);
466 472
473void drm_vblank_off(struct drm_device *dev, int crtc)
474{
475 unsigned long irqflags;
476
477 spin_lock_irqsave(&dev->vbl_lock, irqflags);
478 DRM_WAKEUP(&dev->vbl_queue[crtc]);
479 dev->vblank_enabled[crtc] = 0;
480 dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
481 spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
482}
483EXPORT_SYMBOL(drm_vblank_off);
484
467/** 485/**
468 * drm_vblank_pre_modeset - account for vblanks across mode sets 486 * drm_vblank_pre_modeset - account for vblanks across mode sets
469 * @dev: DRM device 487 * @dev: DRM device
@@ -550,6 +568,63 @@ out:
550 return ret; 568 return ret;
551} 569}
552 570
571static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
572 union drm_wait_vblank *vblwait,
573 struct drm_file *file_priv)
574{
575 struct drm_pending_vblank_event *e;
576 struct timeval now;
577 unsigned long flags;
578 unsigned int seq;
579
580 e = kzalloc(sizeof *e, GFP_KERNEL);
581 if (e == NULL)
582 return -ENOMEM;
583
584 e->pipe = pipe;
585 e->event.base.type = DRM_EVENT_VBLANK;
586 e->event.base.length = sizeof e->event;
587 e->event.user_data = vblwait->request.signal;
588 e->base.event = &e->event.base;
589 e->base.file_priv = file_priv;
590 e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
591
592 do_gettimeofday(&now);
593 spin_lock_irqsave(&dev->event_lock, flags);
594
595 if (file_priv->event_space < sizeof e->event) {
596 spin_unlock_irqrestore(&dev->event_lock, flags);
597 kfree(e);
598 return -ENOMEM;
599 }
600
601 file_priv->event_space -= sizeof e->event;
602 seq = drm_vblank_count(dev, pipe);
603 if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
604 (seq - vblwait->request.sequence) <= (1 << 23)) {
605 vblwait->request.sequence = seq + 1;
606 vblwait->reply.sequence = vblwait->request.sequence;
607 }
608
609 DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
610 vblwait->request.sequence, seq, pipe);
611
612 e->event.sequence = vblwait->request.sequence;
613 if ((seq - vblwait->request.sequence) <= (1 << 23)) {
614 e->event.tv_sec = now.tv_sec;
615 e->event.tv_usec = now.tv_usec;
616 drm_vblank_put(dev, e->pipe);
617 list_add_tail(&e->base.link, &e->base.file_priv->event_list);
618 wake_up_interruptible(&e->base.file_priv->event_wait);
619 } else {
620 list_add_tail(&e->base.link, &dev->vblank_event_list);
621 }
622
623 spin_unlock_irqrestore(&dev->event_lock, flags);
624
625 return 0;
626}
627
553/** 628/**
554 * Wait for VBLANK. 629 * Wait for VBLANK.
555 * 630 *
@@ -609,6 +684,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
609 goto done; 684 goto done;
610 } 685 }
611 686
687 if (flags & _DRM_VBLANK_EVENT)
688 return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);
689
612 if ((flags & _DRM_VBLANK_NEXTONMISS) && 690 if ((flags & _DRM_VBLANK_NEXTONMISS) &&
613 (seq - vblwait->request.sequence) <= (1<<23)) { 691 (seq - vblwait->request.sequence) <= (1<<23)) {
614 vblwait->request.sequence = seq + 1; 692 vblwait->request.sequence = seq + 1;
@@ -641,6 +719,38 @@ done:
641 return ret; 719 return ret;
642} 720}
643 721
722void drm_handle_vblank_events(struct drm_device *dev, int crtc)
723{
724 struct drm_pending_vblank_event *e, *t;
725 struct timeval now;
726 unsigned long flags;
727 unsigned int seq;
728
729 do_gettimeofday(&now);
730 seq = drm_vblank_count(dev, crtc);
731
732 spin_lock_irqsave(&dev->event_lock, flags);
733
734 list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
735 if (e->pipe != crtc)
736 continue;
737 if ((seq - e->event.sequence) > (1<<23))
738 continue;
739
740 DRM_DEBUG("vblank event on %d, current %d\n",
741 e->event.sequence, seq);
742
743 e->event.sequence = seq;
744 e->event.tv_sec = now.tv_sec;
745 e->event.tv_usec = now.tv_usec;
746 drm_vblank_put(dev, e->pipe);
747 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
748 wake_up_interruptible(&e->base.file_priv->event_wait);
749 }
750
751 spin_unlock_irqrestore(&dev->event_lock, flags);
752}
753
644/** 754/**
645 * drm_handle_vblank - handle a vblank event 755 * drm_handle_vblank - handle a vblank event
646 * @dev: DRM device 756 * @dev: DRM device
@@ -651,7 +761,11 @@ done:
651 */ 761 */
652void drm_handle_vblank(struct drm_device *dev, int crtc) 762void drm_handle_vblank(struct drm_device *dev, int crtc)
653{ 763{
764 if (!dev->num_crtcs)
765 return;
766
654 atomic_inc(&dev->_vblank_count[crtc]); 767 atomic_inc(&dev->_vblank_count[crtc]);
655 DRM_WAKEUP(&dev->vbl_queue[crtc]); 768 DRM_WAKEUP(&dev->vbl_queue[crtc]);
769 drm_handle_vblank_events(dev, crtc);
656} 770}
657EXPORT_SYMBOL(drm_handle_vblank); 771EXPORT_SYMBOL(drm_handle_vblank);