drm: Rip out the racy, unused vblank signal code.

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 <eric@anholt.net>
Requested-by: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Dave Airlie <airlied@linux.ie>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Eric Anholt 2009-01-27 21:19:41 -08:00 committed by Linus Torvalds
parent 152a649b64
commit 30b2363408
3 changed files with 24 additions and 148 deletions

View File

@ -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_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs,
DRM_MEM_DRIVER); 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) * drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) *
dev->num_crtcs, DRM_MEM_DRIVER); dev->num_crtcs, DRM_MEM_DRIVER);
drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * 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, setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
(unsigned long)dev); (unsigned long)dev);
spin_lock_init(&dev->vbl_lock); spin_lock_init(&dev->vbl_lock);
atomic_set(&dev->vbl_signal_pending, 0);
dev->num_crtcs = num_crtcs; dev->num_crtcs = num_crtcs;
dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * 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) if (!dev->vbl_queue)
goto err; 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, dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
DRM_MEM_DRIVER); DRM_MEM_DRIVER);
if (!dev->_vblank_count) if (!dev->_vblank_count)
@ -177,7 +169,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
/* Zero per-crtc vblank stuff */ /* Zero per-crtc vblank stuff */
for (i = 0; i < num_crtcs; i++) { for (i = 0; i < num_crtcs; i++) {
init_waitqueue_head(&dev->vbl_queue[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_count[i], 0);
atomic_set(&dev->vblank_refcount[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. * \param data user argument, pointing to a drm_wait_vblank structure.
* \return zero on success or a negative number on failure. * \return zero on success or a negative number on failure.
* *
* Verifies the IRQ is installed. * This function enables the vblank interrupt on the pipe requested, then
* * sleeps waiting for the requested sequence number to occur, and drops
* If a signal is requested checks if this task has already scheduled the same signal * the vblank interrupt refcount afterwards. (vblank irq disable follows that
* for the same vblank sequence number - nothing to be done in * after a timeout with no further vblank waits scheduled).
* 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().
*/ */
int drm_wait_vblank(struct drm_device *dev, void *data, int drm_wait_vblank(struct drm_device *dev, void *data,
struct drm_file *file_priv) 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)) if ((!dev->pdev->irq) || (!dev->irq_enabled))
return -EINVAL; return -EINVAL;
if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
return -EINVAL;
if (vblwait->request.type & if (vblwait->request.type &
~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
@ -597,68 +586,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
vblwait->request.sequence = seq + 1; 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;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
list_add_tail(&vbl_sig->head, vbl_sigs);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
vblwait->reply.sequence = seq;
} else {
DRM_DEBUG("waiting on vblank count %d, crtc %d\n", DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
vblwait->request.sequence, crtc); vblwait->request.sequence, crtc);
dev->last_vblank_wait[crtc] = vblwait->request.sequence; dev->last_vblank_wait[crtc] = vblwait->request.sequence;
@ -680,53 +607,12 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
} else { } else {
DRM_DEBUG("vblank wait interrupted by signal\n"); DRM_DEBUG("vblank wait interrupted by signal\n");
} }
}
done: done:
drm_vblank_put(dev, crtc); drm_vblank_put(dev, crtc);
return ret; return ret;
} }
/**
* 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 * drm_handle_vblank - handle a vblank event
* @dev: DRM device * @dev: DRM device
@ -739,6 +625,5 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
{ {
atomic_inc(&dev->_vblank_count[crtc]); atomic_inc(&dev->_vblank_count[crtc]);
DRM_WAKEUP(&dev->vbl_queue[crtc]); DRM_WAKEUP(&dev->vbl_queue[crtc]);
drm_vbl_send_signals(dev, crtc);
} }
EXPORT_SYMBOL(drm_handle_vblank); EXPORT_SYMBOL(drm_handle_vblank);

View File

@ -458,7 +458,7 @@ enum drm_vblank_seq_type {
_DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */
_DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
_DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _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) #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)

View File

@ -545,13 +545,6 @@ struct drm_ctx_list {
struct drm_file *tag; /**< associated fd private data */ 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 */ /* location of GART table */
#define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_MAIN 1
#define DRM_ATI_GART_FB 2 #define DRM_ATI_GART_FB 2
@ -903,8 +896,6 @@ struct drm_device {
wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ 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) */ atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */
spinlock_t vbl_lock; 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 */ atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */
u32 *last_vblank; /* protected by dev->vbl_lock, used */ u32 *last_vblank; /* protected by dev->vbl_lock, used */
/* for wraparound handling */ /* for wraparound handling */