OSDN Git Service

BSD: change drm_locked_task*() to use the same scheme as linux.
authorOwain Gordon Ainsworth <oga@openbsd.org>
Mon, 7 Jul 2008 16:23:48 +0000 (17:23 +0100)
committerRobert Noland <rnoland@2hip.net>
Thu, 17 Jul 2008 01:37:39 +0000 (21:37 -0400)
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>
bsd-core/drmP.h
bsd-core/drm_drv.c
bsd-core/drm_irq.c
bsd-core/drm_lock.c

index 88ea4e6..65d7fae 100644 (file)
@@ -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          */
index 740a8b5..9bd6079 100644 (file)
@@ -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),
index c3ecd28..a066cfc 100644 (file)
@@ -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);
 }
index 9101dec..80ebb71 100644 (file)
@@ -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();