Simple replacement for hardware lock in some cases.
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Sat, 20 Oct 2007 14:49:43 +0000 (16:49 +0200)
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Sat, 20 Oct 2007 14:49:43 +0000 (16:49 +0200)
Fix i915 since last commit.

libdrm/xf86drm.c
linux-core/Makefile.kernel
linux-core/drm_bo.c
linux-core/drm_bo_lock2.c [new file with mode: 0644]
linux-core/drm_objects.h
linux-core/drm_stub.c
shared-core/drm.h
shared-core/i915_dma.c

index a8e054d..b61c225 100644 (file)
@@ -2815,13 +2815,19 @@ int drmMMTakedown(int fd, unsigned memType)
     return 0;  
 }
 
-int drmMMLock(int fd, unsigned memType)
+/*
+ * If this function returns an error, and lockBM was set to 1,
+ * the buffer manager is NOT locked.
+ */
+
+int drmMMLock(int fd, unsigned memType, int lockBM)
 {
     struct drm_mm_type_arg arg;
     int ret;
 
     memset(&arg, 0, sizeof(arg));
     arg.mem_type = memType;
+    arg.lock_unlock_bm = lock_bm;
 
     do{
         ret = ioctl(fd, DRM_IOCTL_MM_LOCK, &arg);
@@ -2830,7 +2836,7 @@ int drmMMLock(int fd, unsigned memType)
     return (ret) ? -errno : 0;
 }
 
-int drmMMUnlock(int fd, unsigned memType)
+int drmMMUnlock(int fd, unsigned memType, int unlockBM)
 {
     struct drm_mm_type_arg arg;
     int ret;
@@ -2838,6 +2844,7 @@ int drmMMUnlock(int fd, unsigned memType)
     memset(&arg, 0, sizeof(arg));
     
     arg.mem_type = memType;
+    arg.lock_unlock_bm = unlockBM;
 
     do{
        ret = ioctl(fd, DRM_IOCTL_MM_UNLOCK, &arg);
index 715454b..86b225f 100644 (file)
@@ -13,7 +13,7 @@ drm-objs    := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
                drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \
                drm_memory_debug.o ati_pcigart.o drm_sman.o \
                drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \
-               drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o
+               drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_bo_lock2.o
 tdfx-objs   := tdfx_drv.o
 r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
index 35ac8a0..a2a0291 100644 (file)
@@ -1768,11 +1768,16 @@ int drm_bo_setstatus_ioctl(struct drm_device *dev,
        struct drm_bo_info_req *req = &arg->d.req;
        struct drm_bo_info_rep *rep = &arg->d.rep;
        int ret;
+
        if (!dev->bm.initialized) {
                DRM_ERROR("Buffer object manager is not initialized.\n");
                return -EINVAL;
        }
 
+       ret = drm_bo_read_lock(&dev->bm.bm_lock);
+       if (ret)
+               return ret;
+
        ret = drm_bo_handle_validate(file_priv, req->handle, req->fence_class,
                                     req->flags,
                                     req->mask,
@@ -1780,6 +1785,7 @@ int drm_bo_setstatus_ioctl(struct drm_device *dev,
                                     1,
                                     rep, NULL);
 
+       (void) drm_bo_read_unlock(&dev->bm.bm_lock);
        if (ret)
                return ret;
 
@@ -1898,7 +1904,8 @@ int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *
 
 static int drm_bo_leave_list(struct drm_buffer_object * bo,
                             uint32_t mem_type,
-                            int free_pinned, int allow_errors)
+                            int free_pinned,
+                            int allow_errors)
 {
        struct drm_device *dev = bo->dev;
        int ret = 0;
@@ -2150,7 +2157,6 @@ int drm_bo_driver_finish(struct drm_device * dev)
        unsigned i = DRM_BO_MEM_TYPES;
        struct drm_mem_type_manager *man;
 
-       mutex_lock(&dev->bm.init_mutex);
        mutex_lock(&dev->struct_mutex);
 
        if (!bm->initialized)
@@ -2190,7 +2196,6 @@ int drm_bo_driver_finish(struct drm_device * dev)
        }
       out:
        mutex_unlock(&dev->struct_mutex);
-       mutex_unlock(&dev->bm.init_mutex);
        return ret;
 }
 
@@ -2207,7 +2212,7 @@ int drm_bo_driver_init(struct drm_device * dev)
        struct drm_buffer_manager *bm = &dev->bm;
        int ret = -EINVAL;
 
-       mutex_lock(&dev->bm.init_mutex);
+       drm_bo_init_lock(&bm->bm_lock);
        mutex_lock(&dev->struct_mutex);
        if (!driver)
                goto out_unlock;
@@ -2233,7 +2238,6 @@ int drm_bo_driver_init(struct drm_device * dev)
        INIT_LIST_HEAD(&bm->ddestroy);
       out_unlock:
        mutex_unlock(&dev->struct_mutex);
-       mutex_unlock(&dev->bm.init_mutex);
        return ret;
 }
 
@@ -2252,6 +2256,10 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
        }
 
        ret = -EINVAL;
+       ret = drm_bo_write_lock(&bm->bm_lock, file_priv);
+       if (ret)
+               return ret;
+
        if (arg->magic != DRM_BO_INIT_MAGIC) {
                DRM_ERROR("You are using an old libdrm that is not compatible with\n"
                          "\tthe kernel DRM module. Please upgrade your libdrm.\n");
@@ -2271,7 +2279,6 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
                return -EINVAL;
        }
 
-       mutex_lock(&dev->bm.init_mutex);
        mutex_lock(&dev->struct_mutex);
        if (!bm->initialized) {
                DRM_ERROR("DRM memory manager was not initialized.\n");
@@ -2286,7 +2293,8 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
 
 out:
        mutex_unlock(&dev->struct_mutex);
-       mutex_unlock(&dev->bm.init_mutex);
+       (void) drm_bo_write_unlock(&bm->bm_lock, file_priv);
+
        if (ret)
                return ret;
 
@@ -2305,8 +2313,10 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f
                return -EINVAL;
        }
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
-       mutex_lock(&dev->bm.init_mutex);
+       ret = drm_bo_write_lock(&bm->bm_lock, file_priv);
+       if (ret)
+               return ret;
+
        mutex_lock(&dev->struct_mutex);
        ret = -EINVAL;
        if (!bm->initialized) {
@@ -2324,7 +2334,8 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f
        }
 out:
        mutex_unlock(&dev->struct_mutex);
-       mutex_unlock(&dev->bm.init_mutex);
+       (void) drm_bo_write_unlock(&bm->bm_lock, file_priv);
+
        if (ret)
                return ret;
 
@@ -2342,20 +2353,28 @@ int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
                return -EINVAL;
        }
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
-       mutex_lock(&dev->bm.init_mutex);
+       if (arg->lock_unlock_bm) {
+               ret = drm_bo_write_lock(&dev->bm.bm_lock, file_priv);
+               if (ret)
+                       return ret;
+       }
+               
        mutex_lock(&dev->struct_mutex);
        ret = drm_bo_lock_mm(dev, arg->mem_type);
        mutex_unlock(&dev->struct_mutex);
-       mutex_unlock(&dev->bm.init_mutex);
-       if (ret)
+       if (ret) {
+               (void) drm_bo_write_unlock(&dev->bm.bm_lock, file_priv);
                return ret;
+       }
 
        return 0;
 }
 
-int drm_mm_unlock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int drm_mm_unlock_ioctl(struct drm_device *dev, 
+                       void *data, 
+                       struct drm_file *file_priv)
 {
+       struct drm_mm_type_arg *arg = data;
        struct drm_bo_driver *driver = dev->driver->bo_driver;
        int ret;
 
@@ -2364,16 +2383,12 @@ int drm_mm_unlock_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
                return -EINVAL;
        }
 
-       LOCK_TEST_WITH_RETURN(dev, file_priv);
-       mutex_lock(&dev->bm.init_mutex);
-       mutex_lock(&dev->struct_mutex);
-       ret = 0;
-
-       mutex_unlock(&dev->struct_mutex);
-       mutex_unlock(&dev->bm.init_mutex);
-       if (ret)
-               return ret;
-
+       if (arg->lock_unlock_bm) {
+               ret = drm_bo_write_unlock(&dev->bm.bm_lock, file_priv);
+               if (ret)
+                       return ret;
+       }
+               
        return 0;
 }
 
diff --git a/linux-core/drm_bo_lock2.c b/linux-core/drm_bo_lock2.c
new file mode 100644 (file)
index 0000000..73e58bc
--- /dev/null
@@ -0,0 +1,99 @@
+#include "drmP.h"
+
+void drm_bo_init_lock(struct drm_bo_lock *lock)
+{
+       DRM_INIT_WAITQUEUE(&lock->queue);
+       atomic_set(&lock->write_lock_pending, 0);
+       atomic_set(&lock->readers, 0);
+       
+}
+
+void drm_bo_read_unlock(struct drm_bo_lock *lock)
+{
+       if (unlikely(atomic_add_negative(-1, &lock->readers) == 0))
+               BUG();
+       if (atomic_read(&lock->readers) == 0)
+               wake_up_interruptible(&lock->queue);
+}
+
+int drm_bo_read_lock(struct drm_bo_lock *lock)
+{
+       while( unlikely(atomic_read(&lock->write_lock_pending) != 0)) {
+               int ret;
+               ret = wait_event_interruptible
+                       (lock->queue, 
+                        atomic_read(&lock->write_lock_pending) == 0);
+               if (ret)
+                       return -EAGAIN;
+       }
+
+       while( unlikely (!atomic_add_unless(&lock->readers, 1, -1))) {
+               int ret;
+               ret = wait_event_interruptible
+                       (lock->queue, 
+                        atomic_add_unless(&lock->readers, 1, -1));
+               if (ret)
+                       return -EAGAIN;
+       }
+       return 0;
+}
+               
+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);
+       return 0;
+}
+
+static void drm_bo_write_lock_remove(struct drm_file *file_priv, 
+                                    struct drm_user_object *item)
+{
+       struct drm_bo_lock *lock = 
+               container_of(item, struct drm_bo_lock, base);
+       int ret;
+
+       ret = __drm_bo_write_unlock(lock);
+       BUG_ON(ret);
+}
+               
+int drm_bo_write_lock(struct drm_bo_lock *lock, 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;
+
+       while(unlikely(atomic_cmpxchg(&lock->readers, 0, -1) != 0)) {
+               ret = wait_event_interruptible
+                       (lock->queue,
+                        atomic_cmpxchg(&lock->readers, 0, -1) == 0);
+
+               if (ret) {
+                       atomic_set(&lock->write_lock_pending, 0);
+                       wake_up_interruptible(&lock->queue);
+                       return -EAGAIN;
+               }
+       }
+       
+       dev = file_priv->head->dev;
+       mutex_lock(&dev->struct_mutex);
+       ret = drm_add_user_object(file_priv, &lock->base, 0);
+       lock->base.remove = &drm_bo_write_lock_remove;
+       lock->base.type = drm_lock_type;
+       if (ret) 
+               (void) __drm_bo_write_unlock(lock);             
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
+}
+
+
+int drm_bo_write_unlock(struct drm_bo_lock *lock, struct drm_file *file_priv)
+{
+       return drm_user_object_unref(file_priv, lock->base.hash.key, 
+                                    drm_lock_type);
+}
index f153b84..0b937dc 100644 (file)
@@ -43,6 +43,7 @@ struct drm_bo_mem_reg;
 enum drm_object_type {
        drm_fence_type,
        drm_buffer_type,
+       drm_lock_type,
            /*
             * Add other user space object types here.
             */
@@ -414,6 +415,13 @@ struct drm_mem_type_manager {
        void *io_addr;
 };
 
+struct drm_bo_lock {
+       struct drm_user_object base;
+       wait_queue_head_t queue;
+       atomic_t write_lock_pending;
+       atomic_t readers;
+};
+
 #define _DRM_FLAG_MEMTYPE_FIXED     0x00000001 /* Fixed (on-card) PCI memory */
 #define _DRM_FLAG_MEMTYPE_MAPPABLE  0x00000002 /* Memory mappable */
 #define _DRM_FLAG_MEMTYPE_CACHED    0x00000004 /* Cached binding */
@@ -423,8 +431,8 @@ struct drm_mem_type_manager {
 #define _DRM_FLAG_MEMTYPE_CSELECT   0x00000020 /* Select caching */
 
 struct drm_buffer_manager {
-       struct mutex init_mutex;
-       struct mutex evict_mutex;
+        struct drm_bo_lock bm_lock;
+        struct mutex evict_mutex;
        int nice_mode;
        int initialized;
        struct drm_file *last_to_validate;
@@ -603,6 +611,21 @@ extern void drm_regs_init(struct drm_reg_manager *manager,
                                              const void *),
                          void (*reg_destroy)(struct drm_reg *));
 
+/*
+ * drm_bo_lock.c 
+ * Simple replacement for the hardware lock on buffer manager init and clean.
+ */
+
+
+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_write_lock(struct drm_bo_lock *lock, 
+                            struct drm_file *file_priv);
+
+extern int drm_bo_write_unlock(struct drm_bo_lock *lock, 
+                              struct drm_file *file_priv);
+
 #ifdef CONFIG_DEBUG_MUTEXES
 #define DRM_ASSERT_LOCKED(_mutex)                                      \
        BUG_ON(!mutex_is_locked(_mutex) ||                              \
index 07ea91e..9e140ac 100644 (file)
@@ -72,7 +72,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
        init_timer(&dev->timer);
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);
-       mutex_init(&dev->bm.init_mutex);
        mutex_init(&dev->bm.evict_mutex);
 
        idr_init(&dev->drw_idr);
index 0ffd0ad..f88192f 100644 (file)
@@ -872,6 +872,7 @@ struct drm_bo_op_arg {
 
 struct drm_mm_type_arg {
        unsigned int mem_type;
+        int lock_unlock_bm;
 };
 
 struct drm_mm_init_arg {
index 5a51f6e..99d98cd 100644 (file)
@@ -930,6 +930,7 @@ int i915_validate_buffer_list(struct drm_file *file_priv,
                                                 req->bo_req.flags,
                                                 req->bo_req.mask,
                                                 req->bo_req.hint,
+                                                0,
                                                 &rep.bo_info,
                                                 &buffers[buf_count]);