summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdrm/xf86drm.c11
-rw-r--r--linux-core/Makefile.kernel2
-rw-r--r--linux-core/drm_bo.c65
-rw-r--r--linux-core/drm_bo_lock2.c99
-rw-r--r--linux-core/drm_objects.h27
-rw-r--r--linux-core/drm_stub.c1
-rw-r--r--shared-core/drm.h1
-rw-r--r--shared-core/i915_dma.c1
8 files changed, 176 insertions, 31 deletions
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c
index a8e054d9..b61c2250 100644
--- a/libdrm/xf86drm.c
+++ b/libdrm/xf86drm.c
@@ -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);
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel
index 715454bc..86b225f3 100644
--- a/linux-core/Makefile.kernel
+++ b/linux-core/Makefile.kernel
@@ -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
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index 35ac8a0a..a2a0291d 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -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
index 00000000..73e58bc0
--- /dev/null
+++ b/linux-core/drm_bo_lock2.c
@@ -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);
+}
diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h
index f153b84a..0b937dc0 100644
--- a/linux-core/drm_objects.h
+++ b/linux-core/drm_objects.h
@@ -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) || \
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
index 07ea91e0..9e140ac2 100644
--- a/linux-core/drm_stub.c
+++ b/linux-core/drm_stub.c
@@ -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);
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 0ffd0ad5..f88192ff 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -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 {
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index 5a51f6ef..99d98cd3 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -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]);