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.c137
1 files changed, 128 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 0a6f0b3bdc78..a263b7070fc6 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -36,6 +36,7 @@
36#include "drmP.h" 36#include "drmP.h"
37 37
38#include <linux/interrupt.h> /* For task queue support */ 38#include <linux/interrupt.h> /* For task queue support */
39#include <linux/slab.h>
39 40
40#include <linux/vgaarb.h> 41#include <linux/vgaarb.h>
41/** 42/**
@@ -115,6 +116,7 @@ void drm_vblank_cleanup(struct drm_device *dev)
115 116
116 dev->num_crtcs = 0; 117 dev->num_crtcs = 0;
117} 118}
119EXPORT_SYMBOL(drm_vblank_cleanup);
118 120
119int drm_vblank_init(struct drm_device *dev, int num_crtcs) 121int drm_vblank_init(struct drm_device *dev, int num_crtcs)
120{ 122{
@@ -163,7 +165,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
163 } 165 }
164 166
165 dev->vblank_disable_allowed = 0; 167 dev->vblank_disable_allowed = 0;
166
167 return 0; 168 return 0;
168 169
169err: 170err:
@@ -429,15 +430,21 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
429 430
430 spin_lock_irqsave(&dev->vbl_lock, irqflags); 431 spin_lock_irqsave(&dev->vbl_lock, irqflags);
431 /* Going from 0->1 means we have to enable interrupts again */ 432 /* Going from 0->1 means we have to enable interrupts again */
432 if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && 433 if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
433 !dev->vblank_enabled[crtc]) { 434 if (!dev->vblank_enabled[crtc]) {
434 ret = dev->driver->enable_vblank(dev, crtc); 435 ret = dev->driver->enable_vblank(dev, crtc);
435 DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); 436 DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
436 if (ret) 437 if (ret)
438 atomic_dec(&dev->vblank_refcount[crtc]);
439 else {
440 dev->vblank_enabled[crtc] = 1;
441 drm_update_vblank_count(dev, crtc);
442 }
443 }
444 } else {
445 if (!dev->vblank_enabled[crtc]) {
437 atomic_dec(&dev->vblank_refcount[crtc]); 446 atomic_dec(&dev->vblank_refcount[crtc]);
438 else { 447 ret = -EINVAL;
439 dev->vblank_enabled[crtc] = 1;
440 drm_update_vblank_count(dev, crtc);
441 } 448 }
442 } 449 }
443 spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 450 spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
@@ -464,6 +471,19 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
464} 471}
465EXPORT_SYMBOL(drm_vblank_put); 472EXPORT_SYMBOL(drm_vblank_put);
466 473
474void drm_vblank_off(struct drm_device *dev, int crtc)
475{
476 unsigned long irqflags;
477
478 spin_lock_irqsave(&dev->vbl_lock, irqflags);
479 dev->driver->disable_vblank(dev, crtc);
480 DRM_WAKEUP(&dev->vbl_queue[crtc]);
481 dev->vblank_enabled[crtc] = 0;
482 dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
483 spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
484}
485EXPORT_SYMBOL(drm_vblank_off);
486
467/** 487/**
468 * drm_vblank_pre_modeset - account for vblanks across mode sets 488 * drm_vblank_pre_modeset - account for vblanks across mode sets
469 * @dev: DRM device 489 * @dev: DRM device
@@ -475,6 +495,9 @@ EXPORT_SYMBOL(drm_vblank_put);
475 */ 495 */
476void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) 496void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
477{ 497{
498 /* vblank is not initialized (IRQ not installed ?) */
499 if (!dev->num_crtcs)
500 return;
478 /* 501 /*
479 * To avoid all the problems that might happen if interrupts 502 * To avoid all the problems that might happen if interrupts
480 * were enabled/disabled around or between these calls, we just 503 * were enabled/disabled around or between these calls, we just
@@ -550,6 +573,63 @@ out:
550 return ret; 573 return ret;
551} 574}
552 575
576static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
577 union drm_wait_vblank *vblwait,
578 struct drm_file *file_priv)
579{
580 struct drm_pending_vblank_event *e;
581 struct timeval now;
582 unsigned long flags;
583 unsigned int seq;
584
585 e = kzalloc(sizeof *e, GFP_KERNEL);
586 if (e == NULL)
587 return -ENOMEM;
588
589 e->pipe = pipe;
590 e->event.base.type = DRM_EVENT_VBLANK;
591 e->event.base.length = sizeof e->event;
592 e->event.user_data = vblwait->request.signal;
593 e->base.event = &e->event.base;
594 e->base.file_priv = file_priv;
595 e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
596
597 do_gettimeofday(&now);
598 spin_lock_irqsave(&dev->event_lock, flags);
599
600 if (file_priv->event_space < sizeof e->event) {
601 spin_unlock_irqrestore(&dev->event_lock, flags);
602 kfree(e);
603 return -ENOMEM;
604 }
605
606 file_priv->event_space -= sizeof e->event;
607 seq = drm_vblank_count(dev, pipe);
608 if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
609 (seq - vblwait->request.sequence) <= (1 << 23)) {
610 vblwait->request.sequence = seq + 1;
611 vblwait->reply.sequence = vblwait->request.sequence;
612 }
613
614 DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
615 vblwait->request.sequence, seq, pipe);
616
617 e->event.sequence = vblwait->request.sequence;
618 if ((seq - vblwait->request.sequence) <= (1 << 23)) {
619 e->event.tv_sec = now.tv_sec;
620 e->event.tv_usec = now.tv_usec;
621 drm_vblank_put(dev, e->pipe);
622 list_add_tail(&e->base.link, &e->base.file_priv->event_list);
623 wake_up_interruptible(&e->base.file_priv->event_wait);
624 } else {
625 list_add_tail(&e->base.link, &dev->vblank_event_list);
626 }
627
628 spin_unlock_irqrestore(&dev->event_lock, flags);
629
630 return 0;
631}
632
553/** 633/**
554 * Wait for VBLANK. 634 * Wait for VBLANK.
555 * 635 *
@@ -609,6 +689,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
609 goto done; 689 goto done;
610 } 690 }
611 691
692 if (flags & _DRM_VBLANK_EVENT)
693 return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);
694
612 if ((flags & _DRM_VBLANK_NEXTONMISS) && 695 if ((flags & _DRM_VBLANK_NEXTONMISS) &&
613 (seq - vblwait->request.sequence) <= (1<<23)) { 696 (seq - vblwait->request.sequence) <= (1<<23)) {
614 vblwait->request.sequence = seq + 1; 697 vblwait->request.sequence = seq + 1;
@@ -641,6 +724,38 @@ done:
641 return ret; 724 return ret;
642} 725}
643 726
727void drm_handle_vblank_events(struct drm_device *dev, int crtc)
728{
729 struct drm_pending_vblank_event *e, *t;
730 struct timeval now;
731 unsigned long flags;
732 unsigned int seq;
733
734 do_gettimeofday(&now);
735 seq = drm_vblank_count(dev, crtc);
736
737 spin_lock_irqsave(&dev->event_lock, flags);
738
739 list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
740 if (e->pipe != crtc)
741 continue;
742 if ((seq - e->event.sequence) > (1<<23))
743 continue;
744
745 DRM_DEBUG("vblank event on %d, current %d\n",
746 e->event.sequence, seq);
747
748 e->event.sequence = seq;
749 e->event.tv_sec = now.tv_sec;
750 e->event.tv_usec = now.tv_usec;
751 drm_vblank_put(dev, e->pipe);
752 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
753 wake_up_interruptible(&e->base.file_priv->event_wait);
754 }
755
756 spin_unlock_irqrestore(&dev->event_lock, flags);
757}
758
644/** 759/**
645 * drm_handle_vblank - handle a vblank event 760 * drm_handle_vblank - handle a vblank event
646 * @dev: DRM device 761 * @dev: DRM device
@@ -651,7 +766,11 @@ done:
651 */ 766 */
652void drm_handle_vblank(struct drm_device *dev, int crtc) 767void drm_handle_vblank(struct drm_device *dev, int crtc)
653{ 768{
769 if (!dev->num_crtcs)
770 return;
771
654 atomic_inc(&dev->_vblank_count[crtc]); 772 atomic_inc(&dev->_vblank_count[crtc]);
655 DRM_WAKEUP(&dev->vbl_queue[crtc]); 773 DRM_WAKEUP(&dev->vbl_queue[crtc]);
774 drm_handle_vblank_events(dev, crtc);
656} 775}
657EXPORT_SYMBOL(drm_handle_vblank); 776EXPORT_SYMBOL(drm_handle_vblank);