Fix up buffer manager locking.
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Fri, 11 Apr 2008 07:36:12 +0000 (09:36 +0200)
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Mon, 14 Apr 2008 10:13:17 +0000 (12:13 +0200)
linux-core/drm_bo.c
linux-core/drm_bo_lock.c
linux-core/drm_compat.c
linux-core/drm_objects.h
linux-core/drm_vm.c
linux-core/i915_execbuf.c

index 144935d..4ef697b 100644 (file)
@@ -1938,7 +1938,7 @@ int drm_bo_setstatus_ioctl(struct drm_device *dev,
                return -EINVAL;
        }
 
-       ret = drm_bo_read_lock(&dev->bm.bm_lock);
+       ret = drm_bo_read_lock(&dev->bm.bm_lock, 1);
        if (ret)
                return ret;
 
@@ -2449,7 +2449,7 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
                return -EINVAL;
        }
 
-       ret = drm_bo_write_lock(&bm->bm_lock, file_priv);
+       ret = drm_bo_write_lock(&bm->bm_lock, 1, file_priv);
        if (ret)
                return ret;
 
@@ -2500,7 +2500,7 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f
                return -EINVAL;
        }
 
-       ret = drm_bo_write_lock(&bm->bm_lock, file_priv);
+       ret = drm_bo_write_lock(&bm->bm_lock, 0, file_priv);
        if (ret)
                return ret;
 
@@ -2548,7 +2548,7 @@ int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
        }
 
        if (arg->lock_flags & DRM_BO_LOCK_UNLOCK_BM) {
-               ret = drm_bo_write_lock(&dev->bm.bm_lock, file_priv);
+               ret = drm_bo_write_lock(&dev->bm.bm_lock, 1, file_priv);
                if (ret)
                        return ret;
        }
index 2795384..32ebfbe 100644 (file)
@@ -49,7 +49,7 @@
  * unmappable regions to mappable. It's a bug to leave kernel space with the
  * read lock held.
  *
- * Both read- and write lock taking is interruptible for low signal-delivery
+ * Both read- and write lock taking may be interruptible for low signal-delivery
  * latency. The locking functions will return -EAGAIN if interrupted by a
  * signal.
  *
@@ -71,14 +71,20 @@ void drm_bo_read_unlock(struct drm_bo_lock *lock)
        if (unlikely(atomic_add_negative(-1, &lock->readers)))
                BUG();
        if (atomic_read(&lock->readers) == 0)
-               wake_up_interruptible(&lock->queue);
+               wake_up_all(&lock->queue);
 }
 EXPORT_SYMBOL(drm_bo_read_unlock);
 
-int drm_bo_read_lock(struct drm_bo_lock *lock)
+int drm_bo_read_lock(struct drm_bo_lock *lock, int interruptible)
 {
        while (unlikely(atomic_read(&lock->write_lock_pending) != 0)) {
                int ret;
+
+               if (!interruptible) {
+                       wait_event(lock->queue,
+                                  atomic_read(&lock->write_lock_pending) == 0);
+                       continue;
+               }
                ret = wait_event_interruptible
                    (lock->queue, atomic_read(&lock->write_lock_pending) == 0);
                if (ret)
@@ -87,8 +93,14 @@ int drm_bo_read_lock(struct drm_bo_lock *lock)
 
        while (unlikely(!atomic_add_unless(&lock->readers, 1, -1))) {
                int ret;
+
+               if (!interruptible) {
+                       wait_event(lock->queue,
+                                  atomic_read(&lock->readers) != -1);
+                       continue;
+               }
                ret = wait_event_interruptible
-                   (lock->queue, atomic_add_unless(&lock->readers, 1, -1));
+                       (lock->queue, atomic_read(&lock->readers) != -1);
                if (ret)
                        return -EAGAIN;
        }
@@ -100,9 +112,7 @@ static int __drm_bo_write_unlock(struct drm_bo_lock *lock)
 {
        if (unlikely(atomic_cmpxchg(&lock->readers, -1, 0) != -1))
                return -EINVAL;
-       if (unlikely(atomic_cmpxchg(&lock->write_lock_pending, 1, 0) != 1))
-               return -EINVAL;
-       wake_up_interruptible(&lock->queue);
+       wake_up_all(&lock->queue);
        return 0;
 }
 
@@ -116,21 +126,26 @@ static void drm_bo_write_lock_remove(struct drm_file *file_priv,
        BUG_ON(ret);
 }
 
-int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv)
+int drm_bo_write_lock(struct drm_bo_lock *lock, int interruptible,
+                     struct drm_file *file_priv)
 {
        int ret = 0;
        struct drm_device *dev;
 
-       if (unlikely(atomic_cmpxchg(&lock->write_lock_pending, 0, 1) != 0))
-               return -EINVAL;
+       atomic_inc(&lock->write_lock_pending);
 
        while (unlikely(atomic_cmpxchg(&lock->readers, 0, -1) != 0)) {
+               if (!interruptible) {
+                       wait_event(lock->queue,
+                                  atomic_read(&lock->readers) == 0);
+                       continue;
+               }
                ret = wait_event_interruptible
-                   (lock->queue, atomic_cmpxchg(&lock->readers, 0, -1) == 0);
+                   (lock->queue, atomic_read(&lock->readers) == 0);
 
                if (ret) {
-                       atomic_set(&lock->write_lock_pending, 0);
-                       wake_up_interruptible(&lock->queue);
+                       atomic_dec(&lock->write_lock_pending);
+                       wake_up_all(&lock->queue);
                        return -EAGAIN;
                }
        }
@@ -141,6 +156,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv)
         * while holding it.
         */
 
+       atomic_dec(&lock->write_lock_pending);
        dev = file_priv->minor->dev;
        mutex_lock(&dev->struct_mutex);
        ret = drm_add_user_object(file_priv, &lock->base, 0);
index 5dabeae..23e5028 100644 (file)
@@ -213,7 +213,7 @@ static struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
        unsigned long bus_size;
 
        dev = bo->dev;
-       while(drm_bo_read_lock(&dev->bm.bm_lock));
+       drm_bo_read_lock(&dev->bm.bm_lock, 0);
 
        mutex_lock(&bo->mutex);
 
index c32edac..a1f3a18 100644 (file)
@@ -320,6 +320,8 @@ struct drm_ttm {
        int destroy;
        uint32_t mapping_offset;
        struct drm_ttm_backend *be;
+       unsigned long highest_lomem_entry;
+       unsigned long lowest_himem_entry;
        enum {
                ttm_bound,
                ttm_evicted,
@@ -798,8 +800,10 @@ extern void drm_regs_init(struct drm_reg_manager *manager,
 
 extern void drm_bo_init_lock(struct drm_bo_lock *lock);
 extern void drm_bo_read_unlock(struct drm_bo_lock *lock);
-extern int drm_bo_read_lock(struct drm_bo_lock *lock);
+extern int drm_bo_read_lock(struct drm_bo_lock *lock,
+                           int interruptible);
 extern int drm_bo_write_lock(struct drm_bo_lock *lock,
+                            int interruptible,
                             struct drm_file *file_priv);
 
 extern int drm_bo_write_unlock(struct drm_bo_lock *lock,
index ffda828..a09bcdd 100644 (file)
@@ -738,7 +738,7 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
                return NOPFN_SIGBUS;
 
        dev = bo->dev;
-       err = drm_bo_read_lock(&dev->bm.bm_lock);
+       err = drm_bo_read_lock(&dev->bm.bm_lock, 1);
        if (err)
                return NOPFN_REFAULT;
 
index 729ee0c..088a269 100644 (file)
@@ -845,7 +845,7 @@ int i915_execbuffer(struct drm_device *dev, void *data,
        if (exec_buf->num_buffers > dev_priv->max_validate_buffers)
                return -EINVAL;
 
-       ret = drm_bo_read_lock(&dev->bm.bm_lock);
+       ret = drm_bo_read_lock(&dev->bm.bm_lock, 1);
        if (ret)
                return ret;