> Schedule a vblank signal, kill the process, and we'll go walking over freed
> memory. Given that no open-source userland exists using this, nor have I
> ever heard of a consumer, just let this code die.
>
> Signed-off-by: Eric Anholt <[email protected]>
I'm quite happy to push this, if nobody objects with a good reason.
Dave.
> ---
> drivers/gpu/drm/drm_irq.c | 161
> +++++++--------------------------------------
> include/drm/drm.h | 2 +-
> 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 477caa1..69aa0ab 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)
>
> drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs,
> DRM_MEM_DRIVER);
> - drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs,
> - DRM_MEM_DRIVER);
> drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) *
> dev->num_crtcs, DRM_MEM_DRIVER);
> drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
> @@ -132,7 +130,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
> setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
> (unsigned long)dev);
> spin_lock_init(&dev->vbl_lock);
> - atomic_set(&dev->vbl_signal_pending, 0);
> dev->num_crtcs = num_crtcs;
>
> 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)
> if (!dev->vbl_queue)
> goto err;
>
> - dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
> - DRM_MEM_DRIVER);
> - if (!dev->vbl_sigs)
> - goto err;
> -
> dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
> DRM_MEM_DRIVER);
> if (!dev->_vblank_count)
> @@ -177,7 +169,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
> /* Zero per-crtc vblank stuff */
> for (i = 0; i < num_crtcs; i++) {
> init_waitqueue_head(&dev->vbl_queue[i]);
> - INIT_LIST_HEAD(&dev->vbl_sigs[i]);
> atomic_set(&dev->_vblank_count[i], 0);
> atomic_set(&dev->vblank_refcount[i], 0);
> }
> @@ -540,15 +531,10 @@ out:
> * \param data user argument, pointing to a drm_wait_vblank structure.
> * \return zero on success or a negative number on failure.
> *
> - * Verifies the IRQ is installed.
> - *
> - * If a signal is requested checks if this task has already scheduled the
> same signal
> - * for the same vblank sequence number - nothing to be done in
> - * that case. If the number of tasks waiting for the interrupt exceeds 100
> the
> - * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for
> this
> - * task.
> - *
> - * If a signal is not requested, then calls vblank_wait().
> + * This function enables the vblank interrupt on the pipe requested, then
> + * sleeps waiting for the requested sequence number to occur, and drops
> + * the vblank interrupt refcount afterwards. (vblank irq disable follows that
> + * after a timeout with no further vblank waits scheduled).
> */
> int drm_wait_vblank(struct drm_device *dev, void *data,
> struct drm_file *file_priv)
> @@ -560,6 +546,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
> if ((!dev->pdev->irq) || (!dev->irq_enabled))
> return -EINVAL;
>
> + if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
> + return -EINVAL;
> +
> if (vblwait->request.type &
> ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
> 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,
> vblwait->request.sequence = seq + 1;
> }
>
> - if (flags & _DRM_VBLANK_SIGNAL) {
> - unsigned long irqflags;
> - struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
> - struct drm_vbl_sig *vbl_sig;
> -
> - spin_lock_irqsave(&dev->vbl_lock, irqflags);
> -
> - /* Check if this task has already scheduled the same signal
> - * for the same vblank sequence number; nothing to be done in
> - * that case
> - */
> - list_for_each_entry(vbl_sig, vbl_sigs, head) {
> - if (vbl_sig->sequence == vblwait->request.sequence
> - && vbl_sig->info.si_signo ==
> - vblwait->request.signal
> - && vbl_sig->task == current) {
> - spin_unlock_irqrestore(&dev->vbl_lock,
> - irqflags);
> - vblwait->reply.sequence = seq;
> - goto done;
> - }
> - }
> -
> - if (atomic_read(&dev->vbl_signal_pending) >= 100) {
> - spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
> - ret = -EBUSY;
> - goto done;
> - }
> -
> - spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
> -
> - vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig),
> - DRM_MEM_DRIVER);
> - if (!vbl_sig) {
> - ret = -ENOMEM;
> - goto done;
> - }
> -
> - /* Get a refcount on the vblank, which will be released by
> - * drm_vbl_send_signals().
> - */
> - ret = drm_vblank_get(dev, crtc);
> - if (ret) {
> - drm_free(vbl_sig, sizeof(struct drm_vbl_sig),
> - DRM_MEM_DRIVER);
> - goto done;
> - }
> -
> - atomic_inc(&dev->vbl_signal_pending);
> -
> - vbl_sig->sequence = vblwait->request.sequence;
> - vbl_sig->info.si_signo = vblwait->request.signal;
> - vbl_sig->task = current;
> + DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
> + vblwait->request.sequence, crtc);
> + dev->last_vblank_wait[crtc] = vblwait->request.sequence;
> + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
> + (((drm_vblank_count(dev, crtc) -
> + vblwait->request.sequence) <= (1 << 23)) ||
> + !dev->irq_enabled));
>
> - spin_lock_irqsave(&dev->vbl_lock, irqflags);
> -
> - list_add_tail(&vbl_sig->head, vbl_sigs);
> + if (ret != -EINTR) {
> + struct timeval now;
>
> - spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
> + do_gettimeofday(&now);
>
> - vblwait->reply.sequence = seq;
> + vblwait->reply.tval_sec = now.tv_sec;
> + vblwait->reply.tval_usec = now.tv_usec;
> + vblwait->reply.sequence = drm_vblank_count(dev, crtc);
> + DRM_DEBUG("returning %d to client\n",
> + vblwait->reply.sequence);
> } else {
> - DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
> - vblwait->request.sequence, crtc);
> - dev->last_vblank_wait[crtc] = vblwait->request.sequence;
> - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
> - (((drm_vblank_count(dev, crtc) -
> - vblwait->request.sequence) <= (1 << 23)) ||
> - !dev->irq_enabled));
> -
> - if (ret != -EINTR) {
> - struct timeval now;
> -
> - do_gettimeofday(&now);
> -
> - vblwait->reply.tval_sec = now.tv_sec;
> - vblwait->reply.tval_usec = now.tv_usec;
> - vblwait->reply.sequence = drm_vblank_count(dev, crtc);
> - DRM_DEBUG("returning %d to client\n",
> - vblwait->reply.sequence);
> - } else {
> - DRM_DEBUG("vblank wait interrupted by signal\n");
> - }
> + DRM_DEBUG("vblank wait interrupted by signal\n");
> }
>
> done:
> @@ -688,46 +614,6 @@ done:
> }
>
> /**
> - * Send the VBLANK signals.
> - *
> - * \param dev DRM device.
> - * \param crtc CRTC where the vblank event occurred
> - *
> - * Sends a signal for each task in drm_device::vbl_sigs and empties the list.
> - *
> - * If a signal is not requested, then calls vblank_wait().
> - */
> -static void drm_vbl_send_signals(struct drm_device *dev, int crtc)
> -{
> - struct drm_vbl_sig *vbl_sig, *tmp;
> - struct list_head *vbl_sigs;
> - unsigned int vbl_seq;
> - unsigned long flags;
> -
> - spin_lock_irqsave(&dev->vbl_lock, flags);
> -
> - vbl_sigs = &dev->vbl_sigs[crtc];
> - vbl_seq = drm_vblank_count(dev, crtc);
> -
> - list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
> - if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
> - vbl_sig->info.si_code = vbl_seq;
> - send_sig_info(vbl_sig->info.si_signo,
> - &vbl_sig->info, vbl_sig->task);
> -
> - list_del(&vbl_sig->head);
> -
> - drm_free(vbl_sig, sizeof(*vbl_sig),
> - DRM_MEM_DRIVER);
> - atomic_dec(&dev->vbl_signal_pending);
> - drm_vblank_put(dev, crtc);
> - }
> - }
> -
> - spin_unlock_irqrestore(&dev->vbl_lock, flags);
> -}
> -
> -/**
> * drm_handle_vblank - handle a vblank event
> * @dev: DRM device
> * @crtc: where this event occurred
> @@ -739,6 +625,5 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
> {
> atomic_inc(&dev->_vblank_count[crtc]);
> DRM_WAKEUP(&dev->vbl_queue[crtc]);
> - drm_vbl_send_signals(dev, crtc);
> }
> EXPORT_SYMBOL(drm_handle_vblank);
> diff --git a/include/drm/drm.h b/include/drm/drm.h
> index 32e5096..8e77357 100644
> --- a/include/drm/drm.h
> +++ b/include/drm/drm.h
> @@ -458,7 +458,7 @@ enum drm_vblank_seq_type {
> _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip
> */
> _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next
> vblank */
> _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display
> controller */
> - _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
> + _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking,
> unsupported */
> };
>
> #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index afb7858..8190b9b 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -545,13 +545,6 @@ struct drm_ctx_list {
> struct drm_file *tag; /**< associated fd private data */
> };
>
> -struct drm_vbl_sig {
> - struct list_head head;
> - unsigned int sequence;
> - struct siginfo info;
> - struct task_struct *task;
> -};
> -
> /* location of GART table */
> #define DRM_ATI_GART_MAIN 1
> #define DRM_ATI_GART_FB 2
> @@ -903,8 +896,6 @@ struct drm_device {
> wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */
> atomic_t *_vblank_count; /**< number of VBLANK interrupts
> (driver must alloc the right number of counters) */
> spinlock_t vbl_lock;
> - struct list_head *vbl_sigs; /**< signal list to send on VBLANK */
> - atomic_t vbl_signal_pending; /* number of signals pending on all
> crtcs*/
> atomic_t *vblank_refcount; /* number of users of vblank
> interruptsper crtc */
> u32 *last_vblank; /* protected by dev->vbl_lock, used */
> /* for wraparound handling */
>
------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
--
_______________________________________________
Dri-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/dri-devel