mirror of
https://gitlab.freedesktop.org/mesa/drm.git
synced 2025-12-29 06:50:13 +01:00
BSD: change drm_locked_task*() to use the same scheme as linux.
The current code can sleep in an interrupt handler, that is bad. So instead if we can't grab the lock, flag it and run the tasklet on unlock. Signed-off-by: Robert Noland <rnoland@2hip.net>
This commit is contained in:
parent
96580f660e
commit
74cf1f91be
4 changed files with 32 additions and 22 deletions
|
|
@ -739,6 +739,7 @@ struct drm_device {
|
|||
struct mtx dev_lock; /* protects everything else */
|
||||
#endif
|
||||
DRM_SPINTYPE drw_lock;
|
||||
DRM_SPINTYPE tsk_lock;
|
||||
|
||||
/* Usage Counters */
|
||||
int open_count; /* Outstanding files open */
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ int drm_attach(device_t nbdev, drm_pci_id_list_t *idlist)
|
|||
mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF);
|
||||
mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF);
|
||||
mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF);
|
||||
mtx_init(&dev->tsk_lock, "drmtsk", NULL, MTX_DEF);
|
||||
#endif
|
||||
|
||||
id_entry = drm_find_description(pci_get_vendor(dev->device),
|
||||
|
|
|
|||
|
|
@ -578,41 +578,42 @@ static void drm_locked_task(void *context, int pending __unused)
|
|||
{
|
||||
struct drm_device *dev = context;
|
||||
|
||||
DRM_LOCK();
|
||||
for (;;) {
|
||||
int ret;
|
||||
DRM_SPINLOCK(&dev->tsk_lock);
|
||||
|
||||
if (drm_lock_take(&dev->lock.hw_lock->lock,
|
||||
DRM_KERNEL_CONTEXT))
|
||||
{
|
||||
dev->lock.file_priv = NULL; /* kernel owned */
|
||||
dev->lock.lock_time = jiffies;
|
||||
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
|
||||
break; /* Got lock */
|
||||
}
|
||||
|
||||
/* Contention */
|
||||
#if defined(__FreeBSD__) && __FreeBSD_version > 500000
|
||||
ret = mtx_sleep((void *)&dev->lock.lock_queue, &dev->dev_lock,
|
||||
PZERO | PCATCH, "drmlk2", 0);
|
||||
#else
|
||||
ret = tsleep((void *)&dev->lock.lock_queue, PZERO | PCATCH,
|
||||
"drmlk2", 0);
|
||||
#endif
|
||||
if (ret != 0)
|
||||
return;
|
||||
DRM_LOCK(); /* XXX drm_lock_take() should do it's own locking */
|
||||
if (dev->locked_task_call == NULL ||
|
||||
drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT) == 0) {
|
||||
DRM_UNLOCK();
|
||||
DRM_SPINUNLOCK(&dev->tsk_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->lock.file_priv = NULL; /* kernel owned */
|
||||
dev->lock.lock_time = jiffies;
|
||||
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
|
||||
|
||||
DRM_UNLOCK();
|
||||
|
||||
dev->locked_task_call(dev);
|
||||
|
||||
drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
|
||||
|
||||
dev->locked_task_call = NULL;
|
||||
|
||||
DRM_SPINUNLOCK(&dev->tsk_lock);
|
||||
}
|
||||
|
||||
void
|
||||
drm_locked_tasklet(struct drm_device *dev,
|
||||
void (*tasklet)(struct drm_device *dev))
|
||||
{
|
||||
DRM_SPINLOCK(&dev->tsk_lock);
|
||||
if (dev->locked_task_call != NULL) {
|
||||
DRM_SPINUNLOCK(&dev->tsk_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->locked_task_call = tasklet;
|
||||
DRM_SPINUNLOCK(&dev->tsk_lock);
|
||||
taskqueue_enqueue(taskqueue_swi, &dev->locked_task);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,6 +180,13 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
|||
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) != lock->context)
|
||||
return EINVAL;
|
||||
|
||||
DRM_SPINLOCK(&dev->tsk_lock);
|
||||
if (dev->locked_task_call != NULL) {
|
||||
dev->locked_task_call(dev);
|
||||
dev->locked_task_call = NULL;
|
||||
}
|
||||
DRM_SPINUNLOCK(&dev->tsk_lock);
|
||||
|
||||
atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
|
||||
|
||||
DRM_LOCK();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue