From 65dd0e68ff0e0e354925adb7d5fffeb0ffbb485c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 11 Apr 2008 09:36:12 +0200 Subject: Fix up buffer manager locking. --- linux-core/drm_bo.c | 8 ++++---- linux-core/drm_bo_lock.c | 42 +++++++++++++++++++++++++++++------------- linux-core/drm_compat.c | 2 +- linux-core/drm_objects.h | 6 +++++- linux-core/drm_vm.c | 2 +- linux-core/i915_execbuf.c | 2 +- 6 files changed, 41 insertions(+), 21 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 144935d6..4ef697b5 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -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; } diff --git a/linux-core/drm_bo_lock.c b/linux-core/drm_bo_lock.c index 2795384e..32ebfbe2 100644 --- a/linux-core/drm_bo_lock.c +++ b/linux-core/drm_bo_lock.c @@ -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); diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 5dabeaea..23e5028a 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -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); diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index c32edacd..a1f3a18d 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -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, diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index ffda8284..a09bcddb 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -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; diff --git a/linux-core/i915_execbuf.c b/linux-core/i915_execbuf.c index 729ee0c3..088a2693 100644 --- a/linux-core/i915_execbuf.c +++ b/linux-core/i915_execbuf.c @@ -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; -- cgit v1.2.3