Home | History | Annotate | Line # | Download | only in vmwgfx
ttm_lock.c revision 1.1.1.1
      1 /*	$NetBSD: ttm_lock.c,v 1.1.1.1 2021/12/18 20:15:54 riastradh Exp $	*/
      2 
      3 /* SPDX-License-Identifier: GPL-2.0 OR MIT */
      4 /**************************************************************************
      5  *
      6  * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
      7  * All Rights Reserved.
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining a
     10  * copy of this software and associated documentation files (the
     11  * "Software"), to deal in the Software without restriction, including
     12  * without limitation the rights to use, copy, modify, merge, publish,
     13  * distribute, sub license, and/or sell copies of the Software, and to
     14  * permit persons to whom the Software is furnished to do so, subject to
     15  * the following conditions:
     16  *
     17  * The above copyright notice and this permission notice (including the
     18  * next paragraph) shall be included in all copies or substantial portions
     19  * of the Software.
     20  *
     21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     23  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     24  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     25  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     26  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     27  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     28  *
     29  **************************************************************************/
     30 /*
     31  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: ttm_lock.c,v 1.1.1.1 2021/12/18 20:15:54 riastradh Exp $");
     36 
     37 #include <linux/atomic.h>
     38 #include <linux/errno.h>
     39 #include <linux/wait.h>
     40 #include <linux/sched/signal.h>
     41 #include "ttm_lock.h"
     42 #include "ttm_object.h"
     43 
     44 #define TTM_WRITE_LOCK_PENDING    (1 << 0)
     45 #define TTM_VT_LOCK_PENDING       (1 << 1)
     46 #define TTM_SUSPEND_LOCK_PENDING  (1 << 2)
     47 #define TTM_VT_LOCK               (1 << 3)
     48 #define TTM_SUSPEND_LOCK          (1 << 4)
     49 
     50 void ttm_lock_init(struct ttm_lock *lock)
     51 {
     52 	spin_lock_init(&lock->lock);
     53 	init_waitqueue_head(&lock->queue);
     54 	lock->rw = 0;
     55 	lock->flags = 0;
     56 }
     57 
     58 void ttm_read_unlock(struct ttm_lock *lock)
     59 {
     60 	spin_lock(&lock->lock);
     61 	if (--lock->rw == 0)
     62 		wake_up_all(&lock->queue);
     63 	spin_unlock(&lock->lock);
     64 }
     65 
     66 static bool __ttm_read_lock(struct ttm_lock *lock)
     67 {
     68 	bool locked = false;
     69 
     70 	spin_lock(&lock->lock);
     71 	if (lock->rw >= 0 && lock->flags == 0) {
     72 		++lock->rw;
     73 		locked = true;
     74 	}
     75 	spin_unlock(&lock->lock);
     76 	return locked;
     77 }
     78 
     79 int ttm_read_lock(struct ttm_lock *lock, bool interruptible)
     80 {
     81 	int ret = 0;
     82 
     83 	if (interruptible)
     84 		ret = wait_event_interruptible(lock->queue,
     85 					       __ttm_read_lock(lock));
     86 	else
     87 		wait_event(lock->queue, __ttm_read_lock(lock));
     88 	return ret;
     89 }
     90 
     91 static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked)
     92 {
     93 	bool block = true;
     94 
     95 	*locked = false;
     96 
     97 	spin_lock(&lock->lock);
     98 	if (lock->rw >= 0 && lock->flags == 0) {
     99 		++lock->rw;
    100 		block = false;
    101 		*locked = true;
    102 	} else if (lock->flags == 0) {
    103 		block = false;
    104 	}
    105 	spin_unlock(&lock->lock);
    106 
    107 	return !block;
    108 }
    109 
    110 int ttm_read_trylock(struct ttm_lock *lock, bool interruptible)
    111 {
    112 	int ret = 0;
    113 	bool locked;
    114 
    115 	if (interruptible)
    116 		ret = wait_event_interruptible
    117 			(lock->queue, __ttm_read_trylock(lock, &locked));
    118 	else
    119 		wait_event(lock->queue, __ttm_read_trylock(lock, &locked));
    120 
    121 	if (unlikely(ret != 0)) {
    122 		BUG_ON(locked);
    123 		return ret;
    124 	}
    125 
    126 	return (locked) ? 0 : -EBUSY;
    127 }
    128 
    129 void ttm_write_unlock(struct ttm_lock *lock)
    130 {
    131 	spin_lock(&lock->lock);
    132 	lock->rw = 0;
    133 	wake_up_all(&lock->queue);
    134 	spin_unlock(&lock->lock);
    135 }
    136 
    137 static bool __ttm_write_lock(struct ttm_lock *lock)
    138 {
    139 	bool locked = false;
    140 
    141 	spin_lock(&lock->lock);
    142 	if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) {
    143 		lock->rw = -1;
    144 		lock->flags &= ~TTM_WRITE_LOCK_PENDING;
    145 		locked = true;
    146 	} else {
    147 		lock->flags |= TTM_WRITE_LOCK_PENDING;
    148 	}
    149 	spin_unlock(&lock->lock);
    150 	return locked;
    151 }
    152 
    153 int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
    154 {
    155 	int ret = 0;
    156 
    157 	if (interruptible) {
    158 		ret = wait_event_interruptible(lock->queue,
    159 					       __ttm_write_lock(lock));
    160 		if (unlikely(ret != 0)) {
    161 			spin_lock(&lock->lock);
    162 			lock->flags &= ~TTM_WRITE_LOCK_PENDING;
    163 			wake_up_all(&lock->queue);
    164 			spin_unlock(&lock->lock);
    165 		}
    166 	} else
    167 		wait_event(lock->queue, __ttm_write_lock(lock));
    168 
    169 	return ret;
    170 }
    171 
    172 void ttm_suspend_unlock(struct ttm_lock *lock)
    173 {
    174 	spin_lock(&lock->lock);
    175 	lock->flags &= ~TTM_SUSPEND_LOCK;
    176 	wake_up_all(&lock->queue);
    177 	spin_unlock(&lock->lock);
    178 }
    179 
    180 static bool __ttm_suspend_lock(struct ttm_lock *lock)
    181 {
    182 	bool locked = false;
    183 
    184 	spin_lock(&lock->lock);
    185 	if (lock->rw == 0) {
    186 		lock->flags &= ~TTM_SUSPEND_LOCK_PENDING;
    187 		lock->flags |= TTM_SUSPEND_LOCK;
    188 		locked = true;
    189 	} else {
    190 		lock->flags |= TTM_SUSPEND_LOCK_PENDING;
    191 	}
    192 	spin_unlock(&lock->lock);
    193 	return locked;
    194 }
    195 
    196 void ttm_suspend_lock(struct ttm_lock *lock)
    197 {
    198 	wait_event(lock->queue, __ttm_suspend_lock(lock));
    199 }
    200