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:
parent
152a649b64
commit
30b2363408
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue