diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/gpu/drm/drm_irq.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 137 |
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 | } |
119 | EXPORT_SYMBOL(drm_vblank_cleanup); | ||
118 | 120 | ||
119 | int drm_vblank_init(struct drm_device *dev, int num_crtcs) | 121 | int 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 | ||
169 | err: | 170 | err: |
@@ -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 | } |
465 | EXPORT_SYMBOL(drm_vblank_put); | 472 | EXPORT_SYMBOL(drm_vblank_put); |
466 | 473 | ||
474 | void 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 | } | ||
485 | EXPORT_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 | */ |
476 | void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) | 496 | void 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 | ||
576 | static 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 | ||
727 | void 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 | */ |
652 | void drm_handle_vblank(struct drm_device *dev, int crtc) | 767 | void 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 | } |
657 | EXPORT_SYMBOL(drm_handle_vblank); | 776 | EXPORT_SYMBOL(drm_handle_vblank); |