summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwain Gordon Ainsworth <oga@openbsd.org>2008-07-07 17:23:48 +0100
committerRobert Noland <rnoland@2hip.net>2008-07-16 21:37:39 -0400
commit74cf1f91be7f4139601624af0343e3d411190dec (patch)
tree05b856fe8ee275c8c153f89c5a85ef56d7ea580e
parent96580f660e5509dcf6c34de5630e3d36b156bcd5 (diff)
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>
-rw-r--r--bsd-core/drmP.h1
-rw-r--r--bsd-core/drm_drv.c1
-rw-r--r--bsd-core/drm_irq.c45
-rw-r--r--bsd-core/drm_lock.c7
4 files changed, 32 insertions, 22 deletions
diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h
index 88ea4e69..65d7fae4 100644
--- a/bsd-core/drmP.h
+++ b/bsd-core/drmP.h
@@ -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 */
diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c
index 740a8b57..9bd6079f 100644
--- a/bsd-core/drm_drv.c
+++ b/bsd-core/drm_drv.c
@@ -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),
diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c
index c3ecd28b..a066cfc9 100644
--- a/bsd-core/drm_irq.c
+++ b/bsd-core/drm_irq.c
@@ -578,41 +578,42 @@ static void drm_locked_task(void *context, int pending __unused)
{
struct drm_device *dev = context;
- DRM_LOCK();
- for (;;) {
- int ret;
-
- 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 */
- }
+ DRM_SPINLOCK(&dev->tsk_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);
}
diff --git a/bsd-core/drm_lock.c b/bsd-core/drm_lock.c
index 9101dec8..80ebb71d 100644
--- a/bsd-core/drm_lock.c
+++ b/bsd-core/drm_lock.c
@@ -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();