that.
Reply-To: 

Hi,

I just commited a similar fix for this to OpenBSD. Sleeping in interrupt
handlers is bad. just do the same a the linux code does and flag the
handler to be dealt with on unlock.

I don't have a freebsd machine around, so I don't know if this even
compiles, but the general method has been tested and proven to be sound.

Cheers,
-0-

-- 
Distinctive, adj.:
        A different color or shape than our competitors.
>From 6ae185635d7fcc971dafe2e6e6624efde183c9eb Mon Sep 17 00:00:00 2001
From: Owain Gordon Ainsworth <[EMAIL PROTECTED]>
Date: Mon, 7 Jul 2008 17:23:48 +0100
Subject: [PATCH] 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.
---
 bsd-core/drmP.h     |    1 +
 bsd-core/drm_drv.c  |    1 +
 bsd-core/drm_irq.c  |   45 +++++++++++++++++++++++----------------------
 bsd-core/drm_lock.c |    7 +++++++
 4 files changed, 32 insertions(+), 22 deletions(-)

diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h
index 88ea4e6..65d7fae 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 740a8b5..9bd6079 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 c3ecd28..d0c3d69 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 9101dec..80ebb71 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();
-- 
1.5.5.2

-------------------------------------------------------------------------
Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW!
Studies have shown that voting for your favorite open source project,
along with a healthy diet, reduces your potential for chronic lameness
and boredom. Vote Now at http://www.sourceforge.net/community/cca08
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to