From 48b5eaf303b60077faed09db77785d7a544ac335 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sat, 20 Oct 2007 16:49:43 +0200 Subject: Simple replacement for hardware lock in some cases. Fix i915 since last commit. --- libdrm/xf86drm.c | 11 +++++- linux-core/Makefile.kernel | 2 +- linux-core/drm_bo.c | 65 ++++++++++++++++++------------ linux-core/drm_bo_lock2.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_objects.h | 27 ++++++++++++- linux-core/drm_stub.c | 1 - shared-core/drm.h | 1 + shared-core/i915_dma.c | 1 + 8 files changed, 176 insertions(+), 31 deletions(-) create mode 100644 linux-core/drm_bo_lock2.c 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]); -- cgit v1.2.3