Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.3-rc4 294 lines 7.0 kB view raw
1/* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2/************************************************************************** 3 * 4 * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28/* 29 * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> 30 */ 31 32#include <drm/ttm/ttm_module.h> 33#include <linux/atomic.h> 34#include <linux/errno.h> 35#include <linux/wait.h> 36#include <linux/sched/signal.h> 37#include "ttm_lock.h" 38#include "ttm_object.h" 39 40#define TTM_WRITE_LOCK_PENDING (1 << 0) 41#define TTM_VT_LOCK_PENDING (1 << 1) 42#define TTM_SUSPEND_LOCK_PENDING (1 << 2) 43#define TTM_VT_LOCK (1 << 3) 44#define TTM_SUSPEND_LOCK (1 << 4) 45 46void ttm_lock_init(struct ttm_lock *lock) 47{ 48 spin_lock_init(&lock->lock); 49 init_waitqueue_head(&lock->queue); 50 lock->rw = 0; 51 lock->flags = 0; 52 lock->kill_takers = false; 53 lock->signal = SIGKILL; 54} 55 56void ttm_read_unlock(struct ttm_lock *lock) 57{ 58 spin_lock(&lock->lock); 59 if (--lock->rw == 0) 60 wake_up_all(&lock->queue); 61 spin_unlock(&lock->lock); 62} 63 64static bool __ttm_read_lock(struct ttm_lock *lock) 65{ 66 bool locked = false; 67 68 spin_lock(&lock->lock); 69 if (unlikely(lock->kill_takers)) { 70 send_sig(lock->signal, current, 0); 71 spin_unlock(&lock->lock); 72 return false; 73 } 74 if (lock->rw >= 0 && lock->flags == 0) { 75 ++lock->rw; 76 locked = true; 77 } 78 spin_unlock(&lock->lock); 79 return locked; 80} 81 82int ttm_read_lock(struct ttm_lock *lock, bool interruptible) 83{ 84 int ret = 0; 85 86 if (interruptible) 87 ret = wait_event_interruptible(lock->queue, 88 __ttm_read_lock(lock)); 89 else 90 wait_event(lock->queue, __ttm_read_lock(lock)); 91 return ret; 92} 93 94static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked) 95{ 96 bool block = true; 97 98 *locked = false; 99 100 spin_lock(&lock->lock); 101 if (unlikely(lock->kill_takers)) { 102 send_sig(lock->signal, current, 0); 103 spin_unlock(&lock->lock); 104 return false; 105 } 106 if (lock->rw >= 0 && lock->flags == 0) { 107 ++lock->rw; 108 block = false; 109 *locked = true; 110 } else if (lock->flags == 0) { 111 block = false; 112 } 113 spin_unlock(&lock->lock); 114 115 return !block; 116} 117 118int ttm_read_trylock(struct ttm_lock *lock, bool interruptible) 119{ 120 int ret = 0; 121 bool locked; 122 123 if (interruptible) 124 ret = wait_event_interruptible 125 (lock->queue, __ttm_read_trylock(lock, &locked)); 126 else 127 wait_event(lock->queue, __ttm_read_trylock(lock, &locked)); 128 129 if (unlikely(ret != 0)) { 130 BUG_ON(locked); 131 return ret; 132 } 133 134 return (locked) ? 0 : -EBUSY; 135} 136 137void ttm_write_unlock(struct ttm_lock *lock) 138{ 139 spin_lock(&lock->lock); 140 lock->rw = 0; 141 wake_up_all(&lock->queue); 142 spin_unlock(&lock->lock); 143} 144 145static bool __ttm_write_lock(struct ttm_lock *lock) 146{ 147 bool locked = false; 148 149 spin_lock(&lock->lock); 150 if (unlikely(lock->kill_takers)) { 151 send_sig(lock->signal, current, 0); 152 spin_unlock(&lock->lock); 153 return false; 154 } 155 if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) { 156 lock->rw = -1; 157 lock->flags &= ~TTM_WRITE_LOCK_PENDING; 158 locked = true; 159 } else { 160 lock->flags |= TTM_WRITE_LOCK_PENDING; 161 } 162 spin_unlock(&lock->lock); 163 return locked; 164} 165 166int ttm_write_lock(struct ttm_lock *lock, bool interruptible) 167{ 168 int ret = 0; 169 170 if (interruptible) { 171 ret = wait_event_interruptible(lock->queue, 172 __ttm_write_lock(lock)); 173 if (unlikely(ret != 0)) { 174 spin_lock(&lock->lock); 175 lock->flags &= ~TTM_WRITE_LOCK_PENDING; 176 wake_up_all(&lock->queue); 177 spin_unlock(&lock->lock); 178 } 179 } else 180 wait_event(lock->queue, __ttm_write_lock(lock)); 181 182 return ret; 183} 184 185static int __ttm_vt_unlock(struct ttm_lock *lock) 186{ 187 int ret = 0; 188 189 spin_lock(&lock->lock); 190 if (unlikely(!(lock->flags & TTM_VT_LOCK))) 191 ret = -EINVAL; 192 lock->flags &= ~TTM_VT_LOCK; 193 wake_up_all(&lock->queue); 194 spin_unlock(&lock->lock); 195 196 return ret; 197} 198 199static void ttm_vt_lock_remove(struct ttm_base_object **p_base) 200{ 201 struct ttm_base_object *base = *p_base; 202 struct ttm_lock *lock = container_of(base, struct ttm_lock, base); 203 int ret; 204 205 *p_base = NULL; 206 ret = __ttm_vt_unlock(lock); 207 BUG_ON(ret != 0); 208} 209 210static bool __ttm_vt_lock(struct ttm_lock *lock) 211{ 212 bool locked = false; 213 214 spin_lock(&lock->lock); 215 if (lock->rw == 0) { 216 lock->flags &= ~TTM_VT_LOCK_PENDING; 217 lock->flags |= TTM_VT_LOCK; 218 locked = true; 219 } else { 220 lock->flags |= TTM_VT_LOCK_PENDING; 221 } 222 spin_unlock(&lock->lock); 223 return locked; 224} 225 226int ttm_vt_lock(struct ttm_lock *lock, 227 bool interruptible, 228 struct ttm_object_file *tfile) 229{ 230 int ret = 0; 231 232 if (interruptible) { 233 ret = wait_event_interruptible(lock->queue, 234 __ttm_vt_lock(lock)); 235 if (unlikely(ret != 0)) { 236 spin_lock(&lock->lock); 237 lock->flags &= ~TTM_VT_LOCK_PENDING; 238 wake_up_all(&lock->queue); 239 spin_unlock(&lock->lock); 240 return ret; 241 } 242 } else 243 wait_event(lock->queue, __ttm_vt_lock(lock)); 244 245 /* 246 * Add a base-object, the destructor of which will 247 * make sure the lock is released if the client dies 248 * while holding it. 249 */ 250 251 ret = ttm_base_object_init(tfile, &lock->base, false, 252 ttm_lock_type, &ttm_vt_lock_remove, NULL); 253 if (ret) 254 (void)__ttm_vt_unlock(lock); 255 else 256 lock->vt_holder = tfile; 257 258 return ret; 259} 260 261int ttm_vt_unlock(struct ttm_lock *lock) 262{ 263 return ttm_ref_object_base_unref(lock->vt_holder, 264 lock->base.handle, TTM_REF_USAGE); 265} 266 267void ttm_suspend_unlock(struct ttm_lock *lock) 268{ 269 spin_lock(&lock->lock); 270 lock->flags &= ~TTM_SUSPEND_LOCK; 271 wake_up_all(&lock->queue); 272 spin_unlock(&lock->lock); 273} 274 275static bool __ttm_suspend_lock(struct ttm_lock *lock) 276{ 277 bool locked = false; 278 279 spin_lock(&lock->lock); 280 if (lock->rw == 0) { 281 lock->flags &= ~TTM_SUSPEND_LOCK_PENDING; 282 lock->flags |= TTM_SUSPEND_LOCK; 283 locked = true; 284 } else { 285 lock->flags |= TTM_SUSPEND_LOCK_PENDING; 286 } 287 spin_unlock(&lock->lock); 288 return locked; 289} 290 291void ttm_suspend_lock(struct ttm_lock *lock) 292{ 293 wait_event(lock->queue, __ttm_suspend_lock(lock)); 294}