Dude, you're seriously overshooting here. This patch isn't required _at_ _all_ to do cross device sharing/reservations/whatever. We've simply discussed TTM documentation in the context of Maartens work, and I've suggested to include all the TTM kerneldoc into a nice DocBook. That way the kerneldoc stuff gets at least check for correct parameters and similar trivial stuff (core drm sucked royally in that regard). So Maarten jabbed around, I and Dave joined in and since besides vmwgfx nothing else uses it at all I've figured this can't hurt. If you think all the radeon/nouveau/i915/whatever drivers are screwed up beyond repair and need to have the ttm_lock.c file where it is as a stern reminder, I don't care one bit. Personally I think the right solution is to abolish the drm master concept entirely and aim for CONFIG_VT=n. Insulation is a userspace problem which e.g. policykit or whatever the latest thing is can do, or which should be solved for real with per-process address spaces. Everything else smells too fishy for me. So yeah, I don't think the fact that vmwgfx is the only driver with a ->set_master and ->drop_master callback is a good sign, but alas, not my driver and the core impact is negligible. Cheers, Daniel On Fri, Dec 14, 2012 at 4:51 PM, Thomas Hellström <thomas@xxxxxxxxxxxx> wrote: > Nack, > > I'm not against moving the TTM lock away, > when a replacement strategy for the main use case is presented. > > but using wording like "unholy", "scares" just because there is a lack of > understanding or because it gets in the way of implementing cross-device > reservation is a really really bad idea, and FWIW I think it's an even > better idea to refrain from such wording unless you completely understand > the problem and have a better solution in place. > > No other driver uses it, probably simply because the driver writers probably > aren't aware of the use cases or don't implement parallel command > submission. > > And if it weren't for the TTM lock, the cross device work wouldn't have to > consider the case where a client > needs to lock out other reservers, and the cross-device design would suffer. > > The main use cases are: > > 1) If we change master, clients of other masters need to be locked out from > claiming memory resources (particularly VRAM). > 2) If we're about to suspend and have cleaned VRAM, client's need to be > stopped from validating VRAM buffer objects. > 3) If a client needs access to the complete video memory space or need to > defragment, it needs to lock out other reservers in a parallell command > submission environment > > Now, present a better solution to those use cases, and I'll ack this patch > and implement that solution, or > leave the TTM lock in place as a reminder that these things need to be > considered, and that we should have a common solution to them. > > /Thomas > > > > > > On 12/10/12 11:26 AM, Daniel Vetter wrote: >> >> ... it's the only user. Also move the header fil there. >> >> <mlankhorst> but seriously, ttm_lock is best left undocumented since >> nobody should use that unholy thing.. >> <danvet> agreed ;-) >> <danvet> imo we should shovel that under drm/vmwgfx ... >> <airlied> amen >> <airlied> that thing scares me >> <danvet> out of sight, out of mind ... >> >> Signed-off-by: Daniel Vetter <daniel.vetter@xxxxxxxx> >> --- >> drivers/gpu/drm/ttm/Makefile | 2 +- >> drivers/gpu/drm/ttm/ttm_lock.c | 310 >> ----------------------------------- >> drivers/gpu/drm/vmwgfx/Makefile | 2 +- >> drivers/gpu/drm/vmwgfx/ttm_lock.c | 310 >> +++++++++++++++++++++++++++++++++++ >> drivers/gpu/drm/vmwgfx/ttm_lock.h | 247 ++++++++++++++++++++++++++++ >> drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 +- >> include/drm/ttm/ttm_lock.h | 247 ---------------------------- >> 7 files changed, 560 insertions(+), 560 deletions(-) >> delete mode 100644 drivers/gpu/drm/ttm/ttm_lock.c >> create mode 100644 drivers/gpu/drm/vmwgfx/ttm_lock.c >> create mode 100644 drivers/gpu/drm/vmwgfx/ttm_lock.h >> delete mode 100644 include/drm/ttm/ttm_lock.h >> >> diff --git a/drivers/gpu/drm/ttm/Makefile b/drivers/gpu/drm/ttm/Makefile >> index b2b33dd..607a0b6 100644 >> --- a/drivers/gpu/drm/ttm/Makefile >> +++ b/drivers/gpu/drm/ttm/Makefile >> @@ -4,7 +4,7 @@ >> ccflags-y := -Iinclude/drm >> ttm-y := ttm_agp_backend.o ttm_memory.o ttm_tt.o ttm_bo.o \ >> ttm_bo_util.o ttm_bo_vm.o ttm_module.o \ >> - ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o \ >> + ttm_object.o ttm_execbuf_util.o ttm_page_alloc.o \ >> ttm_bo_manager.o >> ifeq ($(CONFIG_SWIOTLB),y) >> diff --git a/drivers/gpu/drm/ttm/ttm_lock.c >> b/drivers/gpu/drm/ttm/ttm_lock.c >> deleted file mode 100644 >> index 3daa9a3..0000000 >> --- a/drivers/gpu/drm/ttm/ttm_lock.c >> +++ /dev/null >> @@ -1,310 +0,0 @@ >> >> -/************************************************************************** >> - * >> - * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA >> - * All Rights Reserved. >> - * >> - * Permission is hereby granted, free of charge, to any person obtaining >> a >> - * copy of this software and associated documentation files (the >> - * "Software"), to deal in the Software without restriction, including >> - * without limitation the rights to use, copy, modify, merge, publish, >> - * distribute, sub license, and/or sell copies of the Software, and to >> - * permit persons to whom the Software is furnished to do so, subject to >> - * the following conditions: >> - * >> - * The above copyright notice and this permission notice (including the >> - * next paragraph) shall be included in all copies or substantial >> portions >> - * of the Software. >> - * >> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >> EXPRESS OR >> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF >> MERCHANTABILITY, >> - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT >> SHALL >> - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY >> CLAIM, >> - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR >> - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR >> THE >> - * USE OR OTHER DEALINGS IN THE SOFTWARE. >> - * >> - >> **************************************************************************/ >> -/* >> - * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> >> - */ >> - >> -#include <drm/ttm/ttm_lock.h> >> -#include <drm/ttm/ttm_module.h> >> -#include <linux/atomic.h> >> -#include <linux/errno.h> >> -#include <linux/wait.h> >> -#include <linux/sched.h> >> -#include <linux/module.h> >> - >> -#define TTM_WRITE_LOCK_PENDING (1 << 0) >> -#define TTM_VT_LOCK_PENDING (1 << 1) >> -#define TTM_SUSPEND_LOCK_PENDING (1 << 2) >> -#define TTM_VT_LOCK (1 << 3) >> -#define TTM_SUSPEND_LOCK (1 << 4) >> - >> -void ttm_lock_init(struct ttm_lock *lock) >> -{ >> - spin_lock_init(&lock->lock); >> - init_waitqueue_head(&lock->queue); >> - lock->rw = 0; >> - lock->flags = 0; >> - lock->kill_takers = false; >> - lock->signal = SIGKILL; >> -} >> -EXPORT_SYMBOL(ttm_lock_init); >> - >> -void ttm_read_unlock(struct ttm_lock *lock) >> -{ >> - spin_lock(&lock->lock); >> - if (--lock->rw == 0) >> - wake_up_all(&lock->queue); >> - spin_unlock(&lock->lock); >> -} >> -EXPORT_SYMBOL(ttm_read_unlock); >> - >> -static bool __ttm_read_lock(struct ttm_lock *lock) >> -{ >> - bool locked = false; >> - >> - spin_lock(&lock->lock); >> - if (unlikely(lock->kill_takers)) { >> - send_sig(lock->signal, current, 0); >> - spin_unlock(&lock->lock); >> - return false; >> - } >> - if (lock->rw >= 0 && lock->flags == 0) { >> - ++lock->rw; >> - locked = true; >> - } >> - spin_unlock(&lock->lock); >> - return locked; >> -} >> - >> -int ttm_read_lock(struct ttm_lock *lock, bool interruptible) >> -{ >> - int ret = 0; >> - >> - if (interruptible) >> - ret = wait_event_interruptible(lock->queue, >> - __ttm_read_lock(lock)); >> - else >> - wait_event(lock->queue, __ttm_read_lock(lock)); >> - return ret; >> -} >> -EXPORT_SYMBOL(ttm_read_lock); >> - >> -static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked) >> -{ >> - bool block = true; >> - >> - *locked = false; >> - >> - spin_lock(&lock->lock); >> - if (unlikely(lock->kill_takers)) { >> - send_sig(lock->signal, current, 0); >> - spin_unlock(&lock->lock); >> - return false; >> - } >> - if (lock->rw >= 0 && lock->flags == 0) { >> - ++lock->rw; >> - block = false; >> - *locked = true; >> - } else if (lock->flags == 0) { >> - block = false; >> - } >> - spin_unlock(&lock->lock); >> - >> - return !block; >> -} >> - >> -int ttm_read_trylock(struct ttm_lock *lock, bool interruptible) >> -{ >> - int ret = 0; >> - bool locked; >> - >> - if (interruptible) >> - ret = wait_event_interruptible >> - (lock->queue, __ttm_read_trylock(lock, &locked)); >> - else >> - wait_event(lock->queue, __ttm_read_trylock(lock, >> &locked)); >> - >> - if (unlikely(ret != 0)) { >> - BUG_ON(locked); >> - return ret; >> - } >> - >> - return (locked) ? 0 : -EBUSY; >> -} >> - >> -void ttm_write_unlock(struct ttm_lock *lock) >> -{ >> - spin_lock(&lock->lock); >> - lock->rw = 0; >> - wake_up_all(&lock->queue); >> - spin_unlock(&lock->lock); >> -} >> -EXPORT_SYMBOL(ttm_write_unlock); >> - >> -static bool __ttm_write_lock(struct ttm_lock *lock) >> -{ >> - bool locked = false; >> - >> - spin_lock(&lock->lock); >> - if (unlikely(lock->kill_takers)) { >> - send_sig(lock->signal, current, 0); >> - spin_unlock(&lock->lock); >> - return false; >> - } >> - if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == >> 0)) { >> - lock->rw = -1; >> - lock->flags &= ~TTM_WRITE_LOCK_PENDING; >> - locked = true; >> - } else { >> - lock->flags |= TTM_WRITE_LOCK_PENDING; >> - } >> - spin_unlock(&lock->lock); >> - return locked; >> -} >> - >> -int ttm_write_lock(struct ttm_lock *lock, bool interruptible) >> -{ >> - int ret = 0; >> - >> - if (interruptible) { >> - ret = wait_event_interruptible(lock->queue, >> - __ttm_write_lock(lock)); >> - if (unlikely(ret != 0)) { >> - spin_lock(&lock->lock); >> - lock->flags &= ~TTM_WRITE_LOCK_PENDING; >> - wake_up_all(&lock->queue); >> - spin_unlock(&lock->lock); >> - } >> - } else >> - wait_event(lock->queue, __ttm_read_lock(lock)); >> - >> - return ret; >> -} >> -EXPORT_SYMBOL(ttm_write_lock); >> - >> -void ttm_write_lock_downgrade(struct ttm_lock *lock) >> -{ >> - spin_lock(&lock->lock); >> - lock->rw = 1; >> - wake_up_all(&lock->queue); >> - spin_unlock(&lock->lock); >> -} >> - >> -static int __ttm_vt_unlock(struct ttm_lock *lock) >> -{ >> - int ret = 0; >> - >> - spin_lock(&lock->lock); >> - if (unlikely(!(lock->flags & TTM_VT_LOCK))) >> - ret = -EINVAL; >> - lock->flags &= ~TTM_VT_LOCK; >> - wake_up_all(&lock->queue); >> - spin_unlock(&lock->lock); >> - >> - return ret; >> -} >> - >> -static void ttm_vt_lock_remove(struct ttm_base_object **p_base) >> -{ >> - struct ttm_base_object *base = *p_base; >> - struct ttm_lock *lock = container_of(base, struct ttm_lock, base); >> - int ret; >> - >> - *p_base = NULL; >> - ret = __ttm_vt_unlock(lock); >> - BUG_ON(ret != 0); >> -} >> - >> -static bool __ttm_vt_lock(struct ttm_lock *lock) >> -{ >> - bool locked = false; >> - >> - spin_lock(&lock->lock); >> - if (lock->rw == 0) { >> - lock->flags &= ~TTM_VT_LOCK_PENDING; >> - lock->flags |= TTM_VT_LOCK; >> - locked = true; >> - } else { >> - lock->flags |= TTM_VT_LOCK_PENDING; >> - } >> - spin_unlock(&lock->lock); >> - return locked; >> -} >> - >> -int ttm_vt_lock(struct ttm_lock *lock, >> - bool interruptible, >> - struct ttm_object_file *tfile) >> -{ >> - int ret = 0; >> - >> - if (interruptible) { >> - ret = wait_event_interruptible(lock->queue, >> - __ttm_vt_lock(lock)); >> - if (unlikely(ret != 0)) { >> - spin_lock(&lock->lock); >> - lock->flags &= ~TTM_VT_LOCK_PENDING; >> - wake_up_all(&lock->queue); >> - spin_unlock(&lock->lock); >> - return ret; >> - } >> - } else >> - wait_event(lock->queue, __ttm_vt_lock(lock)); >> - >> - /* >> - * Add a base-object, the destructor of which will >> - * make sure the lock is released if the client dies >> - * while holding it. >> - */ >> - >> - ret = ttm_base_object_init(tfile, &lock->base, false, >> - ttm_lock_type, &ttm_vt_lock_remove, >> NULL); >> - if (ret) >> - (void)__ttm_vt_unlock(lock); >> - else >> - lock->vt_holder = tfile; >> - >> - return ret; >> -} >> -EXPORT_SYMBOL(ttm_vt_lock); >> - >> -int ttm_vt_unlock(struct ttm_lock *lock) >> -{ >> - return ttm_ref_object_base_unref(lock->vt_holder, >> - lock->base.hash.key, >> TTM_REF_USAGE); >> -} >> -EXPORT_SYMBOL(ttm_vt_unlock); >> - >> -void ttm_suspend_unlock(struct ttm_lock *lock) >> -{ >> - spin_lock(&lock->lock); >> - lock->flags &= ~TTM_SUSPEND_LOCK; >> - wake_up_all(&lock->queue); >> - spin_unlock(&lock->lock); >> -} >> -EXPORT_SYMBOL(ttm_suspend_unlock); >> - >> -static bool __ttm_suspend_lock(struct ttm_lock *lock) >> -{ >> - bool locked = false; >> - >> - spin_lock(&lock->lock); >> - if (lock->rw == 0) { >> - lock->flags &= ~TTM_SUSPEND_LOCK_PENDING; >> - lock->flags |= TTM_SUSPEND_LOCK; >> - locked = true; >> - } else { >> - lock->flags |= TTM_SUSPEND_LOCK_PENDING; >> - } >> - spin_unlock(&lock->lock); >> - return locked; >> -} >> - >> -void ttm_suspend_lock(struct ttm_lock *lock) >> -{ >> - wait_event(lock->queue, __ttm_suspend_lock(lock)); >> -} >> -EXPORT_SYMBOL(ttm_suspend_lock); >> diff --git a/drivers/gpu/drm/vmwgfx/Makefile >> b/drivers/gpu/drm/vmwgfx/Makefile >> index 586869c..74bd973 100644 >> --- a/drivers/gpu/drm/vmwgfx/Makefile >> +++ b/drivers/gpu/drm/vmwgfx/Makefile >> @@ -5,6 +5,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o >> vmwgfx_drv.o \ >> vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ >> vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ >> vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \ >> - vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o >> + vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o ttm_lock.o >> obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o >> diff --git a/drivers/gpu/drm/vmwgfx/ttm_lock.c >> b/drivers/gpu/drm/vmwgfx/ttm_lock.c >> new file mode 100644 >> index 0000000..c859427 >> --- /dev/null >> +++ b/drivers/gpu/drm/vmwgfx/ttm_lock.c >> @@ -0,0 +1,310 @@ >> >> +/************************************************************************** >> + * >> + * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA >> + * All Rights Reserved. >> + * >> + * Permission is hereby granted, free of charge, to any person obtaining >> a >> + * copy of this software and associated documentation files (the >> + * "Software"), to deal in the Software without restriction, including >> + * without limitation the rights to use, copy, modify, merge, publish, >> + * distribute, sub license, and/or sell copies of the Software, and to >> + * permit persons to whom the Software is furnished to do so, subject to >> + * the following conditions: >> + * >> + * The above copyright notice and this permission notice (including the >> + * next paragraph) shall be included in all copies or substantial >> portions >> + * of the Software. >> + * >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >> EXPRESS OR >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF >> MERCHANTABILITY, >> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT >> SHALL >> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY >> CLAIM, >> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR >> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR >> THE >> + * USE OR OTHER DEALINGS IN THE SOFTWARE. >> + * >> + >> **************************************************************************/ >> +/* >> + * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> >> + */ >> + >> +#include "ttm_lock.h" >> +#include <drm/ttm/ttm_module.h> >> +#include <linux/atomic.h> >> +#include <linux/errno.h> >> +#include <linux/wait.h> >> +#include <linux/sched.h> >> +#include <linux/module.h> >> + >> +#define TTM_WRITE_LOCK_PENDING (1 << 0) >> +#define TTM_VT_LOCK_PENDING (1 << 1) >> +#define TTM_SUSPEND_LOCK_PENDING (1 << 2) >> +#define TTM_VT_LOCK (1 << 3) >> +#define TTM_SUSPEND_LOCK (1 << 4) >> + >> +void ttm_lock_init(struct ttm_lock *lock) >> +{ >> + spin_lock_init(&lock->lock); >> + init_waitqueue_head(&lock->queue); >> + lock->rw = 0; >> + lock->flags = 0; >> + lock->kill_takers = false; >> + lock->signal = SIGKILL; >> +} >> +EXPORT_SYMBOL(ttm_lock_init); >> + >> +void ttm_read_unlock(struct ttm_lock *lock) >> +{ >> + spin_lock(&lock->lock); >> + if (--lock->rw == 0) >> + wake_up_all(&lock->queue); >> + spin_unlock(&lock->lock); >> +} >> +EXPORT_SYMBOL(ttm_read_unlock); >> + >> +static bool __ttm_read_lock(struct ttm_lock *lock) >> +{ >> + bool locked = false; >> + >> + spin_lock(&lock->lock); >> + if (unlikely(lock->kill_takers)) { >> + send_sig(lock->signal, current, 0); >> + spin_unlock(&lock->lock); >> + return false; >> + } >> + if (lock->rw >= 0 && lock->flags == 0) { >> + ++lock->rw; >> + locked = true; >> + } >> + spin_unlock(&lock->lock); >> + return locked; >> +} >> + >> +int ttm_read_lock(struct ttm_lock *lock, bool interruptible) >> +{ >> + int ret = 0; >> + >> + if (interruptible) >> + ret = wait_event_interruptible(lock->queue, >> + __ttm_read_lock(lock)); >> + else >> + wait_event(lock->queue, __ttm_read_lock(lock)); >> + return ret; >> +} >> +EXPORT_SYMBOL(ttm_read_lock); >> + >> +static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked) >> +{ >> + bool block = true; >> + >> + *locked = false; >> + >> + spin_lock(&lock->lock); >> + if (unlikely(lock->kill_takers)) { >> + send_sig(lock->signal, current, 0); >> + spin_unlock(&lock->lock); >> + return false; >> + } >> + if (lock->rw >= 0 && lock->flags == 0) { >> + ++lock->rw; >> + block = false; >> + *locked = true; >> + } else if (lock->flags == 0) { >> + block = false; >> + } >> + spin_unlock(&lock->lock); >> + >> + return !block; >> +} >> + >> +int ttm_read_trylock(struct ttm_lock *lock, bool interruptible) >> +{ >> + int ret = 0; >> + bool locked; >> + >> + if (interruptible) >> + ret = wait_event_interruptible >> + (lock->queue, __ttm_read_trylock(lock, &locked)); >> + else >> + wait_event(lock->queue, __ttm_read_trylock(lock, >> &locked)); >> + >> + if (unlikely(ret != 0)) { >> + BUG_ON(locked); >> + return ret; >> + } >> + >> + return (locked) ? 0 : -EBUSY; >> +} >> + >> +void ttm_write_unlock(struct ttm_lock *lock) >> +{ >> + spin_lock(&lock->lock); >> + lock->rw = 0; >> + wake_up_all(&lock->queue); >> + spin_unlock(&lock->lock); >> +} >> +EXPORT_SYMBOL(ttm_write_unlock); >> + >> +static bool __ttm_write_lock(struct ttm_lock *lock) >> +{ >> + bool locked = false; >> + >> + spin_lock(&lock->lock); >> + if (unlikely(lock->kill_takers)) { >> + send_sig(lock->signal, current, 0); >> + spin_unlock(&lock->lock); >> + return false; >> + } >> + if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == >> 0)) { >> + lock->rw = -1; >> + lock->flags &= ~TTM_WRITE_LOCK_PENDING; >> + locked = true; >> + } else { >> + lock->flags |= TTM_WRITE_LOCK_PENDING; >> + } >> + spin_unlock(&lock->lock); >> + return locked; >> +} >> + >> +int ttm_write_lock(struct ttm_lock *lock, bool interruptible) >> +{ >> + int ret = 0; >> + >> + if (interruptible) { >> + ret = wait_event_interruptible(lock->queue, >> + __ttm_write_lock(lock)); >> + if (unlikely(ret != 0)) { >> + spin_lock(&lock->lock); >> + lock->flags &= ~TTM_WRITE_LOCK_PENDING; >> + wake_up_all(&lock->queue); >> + spin_unlock(&lock->lock); >> + } >> + } else >> + wait_event(lock->queue, __ttm_read_lock(lock)); >> + >> + return ret; >> +} >> +EXPORT_SYMBOL(ttm_write_lock); >> + >> +void ttm_write_lock_downgrade(struct ttm_lock *lock) >> +{ >> + spin_lock(&lock->lock); >> + lock->rw = 1; >> + wake_up_all(&lock->queue); >> + spin_unlock(&lock->lock); >> +} >> + >> +static int __ttm_vt_unlock(struct ttm_lock *lock) >> +{ >> + int ret = 0; >> + >> + spin_lock(&lock->lock); >> + if (unlikely(!(lock->flags & TTM_VT_LOCK))) >> + ret = -EINVAL; >> + lock->flags &= ~TTM_VT_LOCK; >> + wake_up_all(&lock->queue); >> + spin_unlock(&lock->lock); >> + >> + return ret; >> +} >> + >> +static void ttm_vt_lock_remove(struct ttm_base_object **p_base) >> +{ >> + struct ttm_base_object *base = *p_base; >> + struct ttm_lock *lock = container_of(base, struct ttm_lock, base); >> + int ret; >> + >> + *p_base = NULL; >> + ret = __ttm_vt_unlock(lock); >> + BUG_ON(ret != 0); >> +} >> + >> +static bool __ttm_vt_lock(struct ttm_lock *lock) >> +{ >> + bool locked = false; >> + >> + spin_lock(&lock->lock); >> + if (lock->rw == 0) { >> + lock->flags &= ~TTM_VT_LOCK_PENDING; >> + lock->flags |= TTM_VT_LOCK; >> + locked = true; >> + } else { >> + lock->flags |= TTM_VT_LOCK_PENDING; >> + } >> + spin_unlock(&lock->lock); >> + return locked; >> +} >> + >> +int ttm_vt_lock(struct ttm_lock *lock, >> + bool interruptible, >> + struct ttm_object_file *tfile) >> +{ >> + int ret = 0; >> + >> + if (interruptible) { >> + ret = wait_event_interruptible(lock->queue, >> + __ttm_vt_lock(lock)); >> + if (unlikely(ret != 0)) { >> + spin_lock(&lock->lock); >> + lock->flags &= ~TTM_VT_LOCK_PENDING; >> + wake_up_all(&lock->queue); >> + spin_unlock(&lock->lock); >> + return ret; >> + } >> + } else >> + wait_event(lock->queue, __ttm_vt_lock(lock)); >> + >> + /* >> + * Add a base-object, the destructor of which will >> + * make sure the lock is released if the client dies >> + * while holding it. >> + */ >> + >> + ret = ttm_base_object_init(tfile, &lock->base, false, >> + ttm_lock_type, &ttm_vt_lock_remove, >> NULL); >> + if (ret) >> + (void)__ttm_vt_unlock(lock); >> + else >> + lock->vt_holder = tfile; >> + >> + return ret; >> +} >> +EXPORT_SYMBOL(ttm_vt_lock); >> + >> +int ttm_vt_unlock(struct ttm_lock *lock) >> +{ >> + return ttm_ref_object_base_unref(lock->vt_holder, >> + lock->base.hash.key, >> TTM_REF_USAGE); >> +} >> +EXPORT_SYMBOL(ttm_vt_unlock); >> + >> +void ttm_suspend_unlock(struct ttm_lock *lock) >> +{ >> + spin_lock(&lock->lock); >> + lock->flags &= ~TTM_SUSPEND_LOCK; >> + wake_up_all(&lock->queue); >> + spin_unlock(&lock->lock); >> +} >> +EXPORT_SYMBOL(ttm_suspend_unlock); >> + >> +static bool __ttm_suspend_lock(struct ttm_lock *lock) >> +{ >> + bool locked = false; >> + >> + spin_lock(&lock->lock); >> + if (lock->rw == 0) { >> + lock->flags &= ~TTM_SUSPEND_LOCK_PENDING; >> + lock->flags |= TTM_SUSPEND_LOCK; >> + locked = true; >> + } else { >> + lock->flags |= TTM_SUSPEND_LOCK_PENDING; >> + } >> + spin_unlock(&lock->lock); >> + return locked; >> +} >> + >> +void ttm_suspend_lock(struct ttm_lock *lock) >> +{ >> + wait_event(lock->queue, __ttm_suspend_lock(lock)); >> +} >> +EXPORT_SYMBOL(ttm_suspend_lock); >> diff --git a/drivers/gpu/drm/vmwgfx/ttm_lock.h >> b/drivers/gpu/drm/vmwgfx/ttm_lock.h >> new file mode 100644 >> index 0000000..2902beb >> --- /dev/null >> +++ b/drivers/gpu/drm/vmwgfx/ttm_lock.h >> @@ -0,0 +1,247 @@ >> >> +/************************************************************************** >> + * >> + * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA >> + * All Rights Reserved. >> + * >> + * Permission is hereby granted, free of charge, to any person obtaining >> a >> + * copy of this software and associated documentation files (the >> + * "Software"), to deal in the Software without restriction, including >> + * without limitation the rights to use, copy, modify, merge, publish, >> + * distribute, sub license, and/or sell copies of the Software, and to >> + * permit persons to whom the Software is furnished to do so, subject to >> + * the following conditions: >> + * >> + * The above copyright notice and this permission notice (including the >> + * next paragraph) shall be included in all copies or substantial >> portions >> + * of the Software. >> + * >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >> EXPRESS OR >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF >> MERCHANTABILITY, >> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT >> SHALL >> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY >> CLAIM, >> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR >> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR >> THE >> + * USE OR OTHER DEALINGS IN THE SOFTWARE. >> + * >> + >> **************************************************************************/ >> +/* >> + * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> >> + */ >> + >> +/** @file ttm_lock.h >> + * This file implements a simple replacement for the buffer manager use >> + * of the DRM heavyweight hardware lock. >> + * The lock is a read-write lock. Taking it in read mode and write mode >> + * is relatively fast, and intended for in-kernel use only. >> + * >> + * The vt mode is used only when there is a need to block all >> + * user-space processes from validating buffers. >> + * It's allowed to leave kernel space with the vt lock held. >> + * If a user-space process dies while having the vt-lock, >> + * it will be released during the file descriptor release. The vt lock >> + * excludes write lock and read lock. >> + * >> + * The suspend mode is used to lock out all TTM users when preparing for >> + * and executing suspend operations. >> + * >> + */ >> + >> +#ifndef _TTM_LOCK_H_ >> +#define _TTM_LOCK_H_ >> + >> +#include <ttm/ttm_object.h> >> +#include <linux/wait.h> >> +#include <linux/atomic.h> >> + >> +/** >> + * struct ttm_lock >> + * >> + * @base: ttm base object used solely to release the lock if the client >> + * holding the lock dies. >> + * @queue: Queue for processes waiting for lock change-of-status. >> + * @lock: Spinlock protecting some lock members. >> + * @rw: Read-write lock counter. Protected by @lock. >> + * @flags: Lock state. Protected by @lock. >> + * @kill_takers: Boolean whether to kill takers of the lock. >> + * @signal: Signal to send when kill_takers is true. >> + */ >> + >> +struct ttm_lock { >> + struct ttm_base_object base; >> + wait_queue_head_t queue; >> + spinlock_t lock; >> + int32_t rw; >> + uint32_t flags; >> + bool kill_takers; >> + int signal; >> + struct ttm_object_file *vt_holder; >> +}; >> + >> + >> +/** >> + * ttm_lock_init >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * Initializes the lock. >> + */ >> +extern void ttm_lock_init(struct ttm_lock *lock); >> + >> +/** >> + * ttm_read_unlock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * >> + * Releases a read lock. >> + */ >> +extern void ttm_read_unlock(struct ttm_lock *lock); >> + >> +/** >> + * ttm_read_lock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * @interruptible: Interruptible sleeping while waiting for a lock. >> + * >> + * Takes the lock in read mode. >> + * Returns: >> + * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> + */ >> +extern int ttm_read_lock(struct ttm_lock *lock, bool interruptible); >> + >> +/** >> + * ttm_read_trylock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * @interruptible: Interruptible sleeping while waiting for a lock. >> + * >> + * Tries to take the lock in read mode. If the lock is already held >> + * in write mode, the function will return -EBUSY. If the lock is held >> + * in vt or suspend mode, the function will sleep until these modes >> + * are unlocked. >> + * >> + * Returns: >> + * -EBUSY The lock was already held in write mode. >> + * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> + */ >> +extern int ttm_read_trylock(struct ttm_lock *lock, bool interruptible); >> + >> +/** >> + * ttm_write_unlock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * >> + * Releases a write lock. >> + */ >> +extern void ttm_write_unlock(struct ttm_lock *lock); >> + >> +/** >> + * ttm_write_lock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * @interruptible: Interruptible sleeping while waiting for a lock. >> + * >> + * Takes the lock in write mode. >> + * Returns: >> + * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> + */ >> +extern int ttm_write_lock(struct ttm_lock *lock, bool interruptible); >> + >> +/** >> + * ttm_lock_downgrade >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * >> + * Downgrades a write lock to a read lock. >> + */ >> +extern void ttm_lock_downgrade(struct ttm_lock *lock); >> + >> +/** >> + * ttm_suspend_lock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * >> + * Takes the lock in suspend mode. Excludes read and write mode. >> + */ >> +extern void ttm_suspend_lock(struct ttm_lock *lock); >> + >> +/** >> + * ttm_suspend_unlock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * >> + * Releases a suspend lock >> + */ >> +extern void ttm_suspend_unlock(struct ttm_lock *lock); >> + >> +/** >> + * ttm_vt_lock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * @interruptible: Interruptible sleeping while waiting for a lock. >> + * @tfile: Pointer to a struct ttm_object_file to register the lock with. >> + * >> + * Takes the lock in vt mode. >> + * Returns: >> + * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> + * -ENOMEM: Out of memory when locking. >> + */ >> +extern int ttm_vt_lock(struct ttm_lock *lock, bool interruptible, >> + struct ttm_object_file *tfile); >> + >> +/** >> + * ttm_vt_unlock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * >> + * Releases a vt lock. >> + * Returns: >> + * -EINVAL If the lock was not held. >> + */ >> +extern int ttm_vt_unlock(struct ttm_lock *lock); >> + >> +/** >> + * ttm_write_unlock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * >> + * Releases a write lock. >> + */ >> +extern void ttm_write_unlock(struct ttm_lock *lock); >> + >> +/** >> + * ttm_write_lock >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * @interruptible: Interruptible sleeping while waiting for a lock. >> + * >> + * Takes the lock in write mode. >> + * Returns: >> + * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> + */ >> +extern int ttm_write_lock(struct ttm_lock *lock, bool interruptible); >> + >> +/** >> + * ttm_lock_set_kill >> + * >> + * @lock: Pointer to a struct ttm_lock >> + * @val: Boolean whether to kill processes taking the lock. >> + * @signal: Signal to send to the process taking the lock. >> + * >> + * The kill-when-taking-lock functionality is used to kill processes that >> keep >> + * on using the TTM functionality when its resources has been taken down, >> for >> + * example when the X server exits. A typical sequence would look like >> this: >> + * - X server takes lock in write mode. >> + * - ttm_lock_set_kill() is called with @val set to true. >> + * - As part of X server exit, TTM resources are taken down. >> + * - X server releases the lock on file release. >> + * - Another dri client wants to render, takes the lock and is killed. >> + * >> + */ >> +static inline void ttm_lock_set_kill(struct ttm_lock *lock, bool val, >> + int signal) >> +{ >> + lock->kill_takers = val; >> + if (val) >> + lock->signal = signal; >> +} >> + >> +#endif >> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h >> b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h >> index 7c6f6e3..94e6de1 100644 >> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h >> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h >> @@ -35,7 +35,7 @@ >> #include <linux/suspend.h> >> #include <drm/ttm/ttm_bo_driver.h> >> #include <drm/ttm/ttm_object.h> >> -#include <drm/ttm/ttm_lock.h> >> +#include "ttm_lock.h" >> #include <drm/ttm/ttm_execbuf_util.h> >> #include <drm/ttm/ttm_module.h> >> #include "vmwgfx_fence.h" >> diff --git a/include/drm/ttm/ttm_lock.h b/include/drm/ttm/ttm_lock.h >> deleted file mode 100644 >> index 2902beb..0000000 >> --- a/include/drm/ttm/ttm_lock.h >> +++ /dev/null >> @@ -1,247 +0,0 @@ >> >> -/************************************************************************** >> - * >> - * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA >> - * All Rights Reserved. >> - * >> - * Permission is hereby granted, free of charge, to any person obtaining >> a >> - * copy of this software and associated documentation files (the >> - * "Software"), to deal in the Software without restriction, including >> - * without limitation the rights to use, copy, modify, merge, publish, >> - * distribute, sub license, and/or sell copies of the Software, and to >> - * permit persons to whom the Software is furnished to do so, subject to >> - * the following conditions: >> - * >> - * The above copyright notice and this permission notice (including the >> - * next paragraph) shall be included in all copies or substantial >> portions >> - * of the Software. >> - * >> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >> EXPRESS OR >> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF >> MERCHANTABILITY, >> - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT >> SHALL >> - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY >> CLAIM, >> - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR >> - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR >> THE >> - * USE OR OTHER DEALINGS IN THE SOFTWARE. >> - * >> - >> **************************************************************************/ >> -/* >> - * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> >> - */ >> - >> -/** @file ttm_lock.h >> - * This file implements a simple replacement for the buffer manager use >> - * of the DRM heavyweight hardware lock. >> - * The lock is a read-write lock. Taking it in read mode and write mode >> - * is relatively fast, and intended for in-kernel use only. >> - * >> - * The vt mode is used only when there is a need to block all >> - * user-space processes from validating buffers. >> - * It's allowed to leave kernel space with the vt lock held. >> - * If a user-space process dies while having the vt-lock, >> - * it will be released during the file descriptor release. The vt lock >> - * excludes write lock and read lock. >> - * >> - * The suspend mode is used to lock out all TTM users when preparing for >> - * and executing suspend operations. >> - * >> - */ >> - >> -#ifndef _TTM_LOCK_H_ >> -#define _TTM_LOCK_H_ >> - >> -#include <ttm/ttm_object.h> >> -#include <linux/wait.h> >> -#include <linux/atomic.h> >> - >> -/** >> - * struct ttm_lock >> - * >> - * @base: ttm base object used solely to release the lock if the client >> - * holding the lock dies. >> - * @queue: Queue for processes waiting for lock change-of-status. >> - * @lock: Spinlock protecting some lock members. >> - * @rw: Read-write lock counter. Protected by @lock. >> - * @flags: Lock state. Protected by @lock. >> - * @kill_takers: Boolean whether to kill takers of the lock. >> - * @signal: Signal to send when kill_takers is true. >> - */ >> - >> -struct ttm_lock { >> - struct ttm_base_object base; >> - wait_queue_head_t queue; >> - spinlock_t lock; >> - int32_t rw; >> - uint32_t flags; >> - bool kill_takers; >> - int signal; >> - struct ttm_object_file *vt_holder; >> -}; >> - >> - >> -/** >> - * ttm_lock_init >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * Initializes the lock. >> - */ >> -extern void ttm_lock_init(struct ttm_lock *lock); >> - >> -/** >> - * ttm_read_unlock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * >> - * Releases a read lock. >> - */ >> -extern void ttm_read_unlock(struct ttm_lock *lock); >> - >> -/** >> - * ttm_read_lock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * @interruptible: Interruptible sleeping while waiting for a lock. >> - * >> - * Takes the lock in read mode. >> - * Returns: >> - * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> - */ >> -extern int ttm_read_lock(struct ttm_lock *lock, bool interruptible); >> - >> -/** >> - * ttm_read_trylock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * @interruptible: Interruptible sleeping while waiting for a lock. >> - * >> - * Tries to take the lock in read mode. If the lock is already held >> - * in write mode, the function will return -EBUSY. If the lock is held >> - * in vt or suspend mode, the function will sleep until these modes >> - * are unlocked. >> - * >> - * Returns: >> - * -EBUSY The lock was already held in write mode. >> - * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> - */ >> -extern int ttm_read_trylock(struct ttm_lock *lock, bool interruptible); >> - >> -/** >> - * ttm_write_unlock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * >> - * Releases a write lock. >> - */ >> -extern void ttm_write_unlock(struct ttm_lock *lock); >> - >> -/** >> - * ttm_write_lock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * @interruptible: Interruptible sleeping while waiting for a lock. >> - * >> - * Takes the lock in write mode. >> - * Returns: >> - * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> - */ >> -extern int ttm_write_lock(struct ttm_lock *lock, bool interruptible); >> - >> -/** >> - * ttm_lock_downgrade >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * >> - * Downgrades a write lock to a read lock. >> - */ >> -extern void ttm_lock_downgrade(struct ttm_lock *lock); >> - >> -/** >> - * ttm_suspend_lock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * >> - * Takes the lock in suspend mode. Excludes read and write mode. >> - */ >> -extern void ttm_suspend_lock(struct ttm_lock *lock); >> - >> -/** >> - * ttm_suspend_unlock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * >> - * Releases a suspend lock >> - */ >> -extern void ttm_suspend_unlock(struct ttm_lock *lock); >> - >> -/** >> - * ttm_vt_lock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * @interruptible: Interruptible sleeping while waiting for a lock. >> - * @tfile: Pointer to a struct ttm_object_file to register the lock with. >> - * >> - * Takes the lock in vt mode. >> - * Returns: >> - * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> - * -ENOMEM: Out of memory when locking. >> - */ >> -extern int ttm_vt_lock(struct ttm_lock *lock, bool interruptible, >> - struct ttm_object_file *tfile); >> - >> -/** >> - * ttm_vt_unlock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * >> - * Releases a vt lock. >> - * Returns: >> - * -EINVAL If the lock was not held. >> - */ >> -extern int ttm_vt_unlock(struct ttm_lock *lock); >> - >> -/** >> - * ttm_write_unlock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * >> - * Releases a write lock. >> - */ >> -extern void ttm_write_unlock(struct ttm_lock *lock); >> - >> -/** >> - * ttm_write_lock >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * @interruptible: Interruptible sleeping while waiting for a lock. >> - * >> - * Takes the lock in write mode. >> - * Returns: >> - * -ERESTARTSYS If interrupted by a signal and interruptible is true. >> - */ >> -extern int ttm_write_lock(struct ttm_lock *lock, bool interruptible); >> - >> -/** >> - * ttm_lock_set_kill >> - * >> - * @lock: Pointer to a struct ttm_lock >> - * @val: Boolean whether to kill processes taking the lock. >> - * @signal: Signal to send to the process taking the lock. >> - * >> - * The kill-when-taking-lock functionality is used to kill processes that >> keep >> - * on using the TTM functionality when its resources has been taken down, >> for >> - * example when the X server exits. A typical sequence would look like >> this: >> - * - X server takes lock in write mode. >> - * - ttm_lock_set_kill() is called with @val set to true. >> - * - As part of X server exit, TTM resources are taken down. >> - * - X server releases the lock on file release. >> - * - Another dri client wants to render, takes the lock and is killed. >> - * >> - */ >> -static inline void ttm_lock_set_kill(struct ttm_lock *lock, bool val, >> - int signal) >> -{ >> - lock->kill_takers = val; >> - if (val) >> - lock->signal = signal; >> -} >> - >> -#endif > > > > -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel