diff options
| -rw-r--r-- | drivers/gpu/drm/drm_irq.c | 161 | ||||
| -rw-r--r-- | include/drm/drm.h | 2 | ||||
| -rw-r--r-- | include/drm/drmP.h | 9 |
3 files changed, 24 insertions, 148 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 477caa1b1e4b..69aa0ab28403 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
| @@ -106,8 +106,6 @@ void drm_vblank_cleanup(struct drm_device *dev) | |||
| 106 | 106 | ||
| 107 | drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, | 107 | drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, |
| 108 | DRM_MEM_DRIVER); | 108 | DRM_MEM_DRIVER); |
| 109 | drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, | ||
| 110 | DRM_MEM_DRIVER); | ||
| 111 | drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * | 109 | drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * |
| 112 | dev->num_crtcs, DRM_MEM_DRIVER); | 110 | dev->num_crtcs, DRM_MEM_DRIVER); |
| 113 | drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * | 111 | drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * |
| @@ -132,7 +130,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
| 132 | setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, | 130 | setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, |
| 133 | (unsigned long)dev); | 131 | (unsigned long)dev); |
| 134 | spin_lock_init(&dev->vbl_lock); | 132 | spin_lock_init(&dev->vbl_lock); |
| 135 | atomic_set(&dev->vbl_signal_pending, 0); | ||
| 136 | dev->num_crtcs = num_crtcs; | 133 | dev->num_crtcs = num_crtcs; |
| 137 | 134 | ||
| 138 | dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, | 135 | dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, |
| @@ -140,11 +137,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
| 140 | if (!dev->vbl_queue) | 137 | if (!dev->vbl_queue) |
| 141 | goto err; | 138 | goto err; |
| 142 | 139 | ||
| 143 | dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, | ||
| 144 | DRM_MEM_DRIVER); | ||
| 145 | if (!dev->vbl_sigs) | ||
| 146 | goto err; | ||
| 147 | |||
| 148 | dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, | 140 | dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, |
| 149 | DRM_MEM_DRIVER); | 141 | DRM_MEM_DRIVER); |
| 150 | if (!dev->_vblank_count) | 142 | if (!dev->_vblank_count) |
| @@ -177,7 +169,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
| 177 | /* Zero per-crtc vblank stuff */ | 169 | /* Zero per-crtc vblank stuff */ |
| 178 | for (i = 0; i < num_crtcs; i++) { | 170 | for (i = 0; i < num_crtcs; i++) { |
| 179 | init_waitqueue_head(&dev->vbl_queue[i]); | 171 | init_waitqueue_head(&dev->vbl_queue[i]); |
| 180 | INIT_LIST_HEAD(&dev->vbl_sigs[i]); | ||
| 181 | atomic_set(&dev->_vblank_count[i], 0); | 172 | atomic_set(&dev->_vblank_count[i], 0); |
| 182 | atomic_set(&dev->vblank_refcount[i], 0); | 173 | atomic_set(&dev->vblank_refcount[i], 0); |
| 183 | } | 174 | } |
| @@ -540,15 +531,10 @@ out: | |||
| 540 | * \param data user argument, pointing to a drm_wait_vblank structure. | 531 | * \param data user argument, pointing to a drm_wait_vblank structure. |
| 541 | * \return zero on success or a negative number on failure. | 532 | * \return zero on success or a negative number on failure. |
| 542 | * | 533 | * |
| 543 | * Verifies the IRQ is installed. | 534 | * This function enables the vblank interrupt on the pipe requested, then |
| 544 | * | 535 | * sleeps waiting for the requested sequence number to occur, and drops |
| 545 | * If a signal is requested checks if this task has already scheduled the same signal | 536 | * the vblank interrupt refcount afterwards. (vblank irq disable follows that |
| 546 | * for the same vblank sequence number - nothing to be done in | 537 | * after a timeout with no further vblank waits scheduled). |
| 547 | * that case. If the number of tasks waiting for the interrupt exceeds 100 the | ||
| 548 | * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this | ||
| 549 | * task. | ||
| 550 | * | ||
| 551 | * If a signal is not requested, then calls vblank_wait(). | ||
| 552 | */ | 538 | */ |
| 553 | int drm_wait_vblank(struct drm_device *dev, void *data, | 539 | int drm_wait_vblank(struct drm_device *dev, void *data, |
| 554 | struct drm_file *file_priv) | 540 | struct drm_file *file_priv) |
| @@ -560,6 +546,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 560 | if ((!dev->pdev->irq) || (!dev->irq_enabled)) | 546 | if ((!dev->pdev->irq) || (!dev->irq_enabled)) |
| 561 | return -EINVAL; | 547 | return -EINVAL; |
| 562 | 548 | ||
| 549 | if (vblwait->request.type & _DRM_VBLANK_SIGNAL) | ||
| 550 | return -EINVAL; | ||
| 551 | |||
| 563 | if (vblwait->request.type & | 552 | if (vblwait->request.type & |
| 564 | ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { | 553 | ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { |
| 565 | DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", | 554 | DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", |
| @@ -597,89 +586,26 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 597 | vblwait->request.sequence = seq + 1; | 586 | vblwait->request.sequence = seq + 1; |
| 598 | } | 587 | } |
| 599 | 588 | ||
| 600 | if (flags & _DRM_VBLANK_SIGNAL) { | 589 | DRM_DEBUG("waiting on vblank count %d, crtc %d\n", |
| 601 | unsigned long irqflags; | 590 | vblwait->request.sequence, crtc); |
| 602 | struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; | 591 | dev->last_vblank_wait[crtc] = vblwait->request.sequence; |
| 603 | struct drm_vbl_sig *vbl_sig; | 592 | DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, |
| 604 | 593 | (((drm_vblank_count(dev, crtc) - | |
| 605 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 594 | vblwait->request.sequence) <= (1 << 23)) || |
| 606 | 595 | !dev->irq_enabled)); | |
| 607 | /* Check if this task has already scheduled the same signal | ||
| 608 | * for the same vblank sequence number; nothing to be done in | ||
| 609 | * that case | ||
| 610 | */ | ||
| 611 | list_for_each_entry(vbl_sig, vbl_sigs, head) { | ||
| 612 | if (vbl_sig->sequence == vblwait->request.sequence | ||
| 613 | && vbl_sig->info.si_signo == | ||
| 614 | vblwait->request.signal | ||
| 615 | && vbl_sig->task == current) { | ||
| 616 | spin_unlock_irqrestore(&dev->vbl_lock, | ||
| 617 | irqflags); | ||
| 618 | vblwait->reply.sequence = seq; | ||
| 619 | goto done; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | |||
| 623 | if (atomic_read(&dev->vbl_signal_pending) >= 100) { | ||
| 624 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 625 | ret = -EBUSY; | ||
| 626 | goto done; | ||
| 627 | } | ||
| 628 | |||
| 629 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 630 | |||
| 631 | vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), | ||
| 632 | DRM_MEM_DRIVER); | ||
| 633 | if (!vbl_sig) { | ||
| 634 | ret = -ENOMEM; | ||
| 635 | goto done; | ||
| 636 | } | ||
| 637 | |||
| 638 | /* Get a refcount on the vblank, which will be released by | ||
| 639 | * drm_vbl_send_signals(). | ||
| 640 | */ | ||
| 641 | ret = drm_vblank_get(dev, crtc); | ||
| 642 | if (ret) { | ||
| 643 | drm_free(vbl_sig, sizeof(struct drm_vbl_sig), | ||
| 644 | DRM_MEM_DRIVER); | ||
| 645 | goto done; | ||
| 646 | } | ||
| 647 | |||
| 648 | atomic_inc(&dev->vbl_signal_pending); | ||
| 649 | |||
| 650 | vbl_sig->sequence = vblwait->request.sequence; | ||
| 651 | vbl_sig->info.si_signo = vblwait->request.signal; | ||
| 652 | vbl_sig->task = current; | ||
| 653 | 596 | ||
| 654 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 597 | if (ret != -EINTR) { |
| 655 | 598 | struct timeval now; | |
| 656 | list_add_tail(&vbl_sig->head, vbl_sigs); | ||
| 657 | 599 | ||
| 658 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 600 | do_gettimeofday(&now); |
| 659 | 601 | ||
| 660 | vblwait->reply.sequence = seq; | 602 | vblwait->reply.tval_sec = now.tv_sec; |
| 603 | vblwait->reply.tval_usec = now.tv_usec; | ||
| 604 | vblwait->reply.sequence = drm_vblank_count(dev, crtc); | ||
| 605 | DRM_DEBUG("returning %d to client\n", | ||
| 606 | vblwait->reply.sequence); | ||
| 661 | } else { | 607 | } else { |
| 662 | DRM_DEBUG("waiting on vblank count %d, crtc %d\n", | 608 | DRM_DEBUG("vblank wait interrupted by signal\n"); |
| 663 | vblwait->request.sequence, crtc); | ||
| 664 | dev->last_vblank_wait[crtc] = vblwait->request.sequence; | ||
| 665 | DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, | ||
| 666 | (((drm_vblank_count(dev, crtc) - | ||
| 667 | vblwait->request.sequence) <= (1 << 23)) || | ||
| 668 | !dev->irq_enabled)); | ||
| 669 | |||
| 670 | if (ret != -EINTR) { | ||
| 671 | struct timeval now; | ||
| 672 | |||
| 673 | do_gettimeofday(&now); | ||
| 674 | |||
| 675 | vblwait->reply.tval_sec = now.tv_sec; | ||
| 676 | vblwait->reply.tval_usec = now.tv_usec; | ||
| 677 | vblwait->reply.sequence = drm_vblank_count(dev, crtc); | ||
| 678 | DRM_DEBUG("returning %d to client\n", | ||
| 679 | vblwait->reply.sequence); | ||
| 680 | } else { | ||
| 681 | DRM_DEBUG("vblank wait interrupted by signal\n"); | ||
| 682 | } | ||
| 683 | } | 609 | } |
| 684 | 610 | ||
| 685 | done: | 611 | done: |
| @@ -688,46 +614,6 @@ done: | |||
| 688 | } | 614 | } |
| 689 | 615 | ||
| 690 | /** | 616 | /** |
| 691 | * Send the VBLANK signals. | ||
| 692 | * | ||
| 693 | * \param dev DRM device. | ||
| 694 | * \param crtc CRTC where the vblank event occurred | ||
| 695 | * | ||
| 696 | * Sends a signal for each task in drm_device::vbl_sigs and empties the list. | ||
| 697 | * | ||
| 698 | * If a signal is not requested, then calls vblank_wait(). | ||
| 699 | */ | ||
| 700 | static void drm_vbl_send_signals(struct drm_device *dev, int crtc) | ||
| 701 | { | ||
| 702 | struct drm_vbl_sig *vbl_sig, *tmp; | ||
| 703 | struct list_head *vbl_sigs; | ||
| 704 | unsigned int vbl_seq; | ||
| 705 | unsigned long flags; | ||
| 706 | |||
| 707 | spin_lock_irqsave(&dev->vbl_lock, flags); | ||
| 708 | |||
| 709 | vbl_sigs = &dev->vbl_sigs[crtc]; | ||
| 710 | vbl_seq = drm_vblank_count(dev, crtc); | ||
| 711 | |||
| 712 | list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { | ||
| 713 | if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { | ||
| 714 | vbl_sig->info.si_code = vbl_seq; | ||
| 715 | send_sig_info(vbl_sig->info.si_signo, | ||
| 716 | &vbl_sig->info, vbl_sig->task); | ||
| 717 | |||
| 718 | list_del(&vbl_sig->head); | ||
| 719 | |||
| 720 | drm_free(vbl_sig, sizeof(*vbl_sig), | ||
| 721 | DRM_MEM_DRIVER); | ||
| 722 | atomic_dec(&dev->vbl_signal_pending); | ||
| 723 | drm_vblank_put(dev, crtc); | ||
| 724 | } | ||
| 725 | } | ||
| 726 | |||
| 727 | spin_unlock_irqrestore(&dev->vbl_lock, flags); | ||
| 728 | } | ||
| 729 | |||
| 730 | /** | ||
| 731 | * drm_handle_vblank - handle a vblank event | 617 | * drm_handle_vblank - handle a vblank event |
| 732 | * @dev: DRM device | 618 | * @dev: DRM device |
| 733 | * @crtc: where this event occurred | 619 | * @crtc: where this event occurred |
| @@ -739,6 +625,5 @@ void drm_handle_vblank(struct drm_device *dev, int crtc) | |||
| 739 | { | 625 | { |
| 740 | atomic_inc(&dev->_vblank_count[crtc]); | 626 | atomic_inc(&dev->_vblank_count[crtc]); |
| 741 | DRM_WAKEUP(&dev->vbl_queue[crtc]); | 627 | DRM_WAKEUP(&dev->vbl_queue[crtc]); |
| 742 | drm_vbl_send_signals(dev, crtc); | ||
| 743 | } | 628 | } |
| 744 | EXPORT_SYMBOL(drm_handle_vblank); | 629 | EXPORT_SYMBOL(drm_handle_vblank); |
diff --git a/include/drm/drm.h b/include/drm/drm.h index 32e5096554e9..8e77357334ad 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h | |||
| @@ -458,7 +458,7 @@ enum drm_vblank_seq_type { | |||
| 458 | _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ | 458 | _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ |
| 459 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ | 459 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ |
| 460 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ | 460 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ |
| 461 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ | 461 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */ |
| 462 | }; | 462 | }; |
| 463 | 463 | ||
| 464 | #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) | 464 | #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index afb7858c068d..8190b9bcc2d9 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
| @@ -545,13 +545,6 @@ struct drm_ctx_list { | |||
| 545 | struct drm_file *tag; /**< associated fd private data */ | 545 | struct drm_file *tag; /**< associated fd private data */ |
| 546 | }; | 546 | }; |
| 547 | 547 | ||
| 548 | struct drm_vbl_sig { | ||
| 549 | struct list_head head; | ||
| 550 | unsigned int sequence; | ||
| 551 | struct siginfo info; | ||
| 552 | struct task_struct *task; | ||
| 553 | }; | ||
| 554 | |||
| 555 | /* location of GART table */ | 548 | /* location of GART table */ |
| 556 | #define DRM_ATI_GART_MAIN 1 | 549 | #define DRM_ATI_GART_MAIN 1 |
| 557 | #define DRM_ATI_GART_FB 2 | 550 | #define DRM_ATI_GART_FB 2 |
| @@ -903,8 +896,6 @@ struct drm_device { | |||
| 903 | wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ | 896 | wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ |
| 904 | atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ | 897 | atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ |
| 905 | spinlock_t vbl_lock; | 898 | spinlock_t vbl_lock; |
| 906 | struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ | ||
| 907 | atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ | ||
| 908 | atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ | 899 | atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ |
| 909 | u32 *last_vblank; /* protected by dev->vbl_lock, used */ | 900 | u32 *last_vblank; /* protected by dev->vbl_lock, used */ |
| 910 | /* for wraparound handling */ | 901 | /* for wraparound handling */ |
