Home | History | Annotate | Line # | Download | only in vmwgfx
      1 /*	$NetBSD: ttm_lock.c,v 1.3 2022/02/17 01:21:02 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.3 2022/02/17 01:21:02 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 	DRM_INIT_WAITQUEUE(&lock->queue, "ttmlock");
     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 		DRM_SPIN_WAKEUP_ALL(&lock->queue, &lock->lock);
     63 	spin_unlock(&lock->lock);
     64 }
     65 
     66 static bool __ttm_read_lock(struct ttm_lock *lock)
     67 {
     68 	bool locked = false;
     69 
     70 	if (lock->rw >= 0 && lock->flags == 0) {
     71 		++lock->rw;
     72 		locked = true;
     73 	}
     74 	return locked;
     75 }
     76 
     77 int ttm_read_lock(struct ttm_lock *lock, bool interruptible)
     78 {
     79 	int ret = 0;
     80 
     81 	spin_lock(&lock->lock);
     82 	if (interruptible)
     83 		DRM_SPIN_WAIT_UNTIL(ret, &lock->queue, &lock->lock,
     84 		    __ttm_read_lock(lock));
     85 	else
     86 		DRM_SPIN_WAIT_NOINTR_UNTIL(ret, &lock->queue, &lock->lock,
     87 		    __ttm_read_lock(lock));
     88 	spin_unlock(&lock->lock);
     89 
     90 	return ret;
     91 }
     92 
     93 static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked)
     94 {
     95 	bool block = true;
     96 
     97 	*locked = false;
     98 
     99 	spin_lock(&lock->lock);
    100 	if (lock->rw >= 0 && lock->flags == 0) {
    101 		++lock->rw;
    102 		block = false;
    103 		*locked = true;
    104 	} else if (lock->flags == 0) {
    105 		block = false;
    106 	}
    107 	spin_unlock(&lock->lock);
    108 
    109 	return !block;
    110 }
    111 
    112 int ttm_read_trylock(struct ttm_lock *lock, bool interruptible)
    113 {
    114 	int ret = 0;
    115 	bool locked;
    116 
    117 	spin_lock(&lock->lock);
    118 	if (interruptible)
    119 		DRM_SPIN_WAIT_UNTIL(ret, &lock->queue, &lock->lock,
    120 		    __ttm_read_trylock(lock, &locked));
    121 	else
    122 		DRM_SPIN_WAIT_NOINTR_UNTIL(ret, &lock->queue, &lock->lock,
    123 		    __ttm_read_trylock(lock, &locked));
    124 	spin_unlock(&lock->lock);
    125 
    126 	if (unlikely(ret != 0)) {
    127 		BUG_ON(locked);
    128 		return ret;
    129 	}
    130 
    131 	return (locked) ? 0 : -EBUSY;
    132 }
    133 
    134 void ttm_write_unlock(struct ttm_lock *lock)
    135 {
    136 	spin_lock(&lock->lock);
    137 	lock->rw = 0;
    138 	DRM_SPIN_WAKEUP_ALL(&lock->queue, &lock->lock);
    139 	spin_unlock(&lock->lock);
    140 }
    141 
    142 static bool __ttm_write_lock(struct ttm_lock *lock)
    143 {
    144 	bool locked = false;
    145 
    146 	spin_lock(&lock->lock);
    147 	if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) {
    148 		lock->rw = -1;
    149 		lock->flags &= ~TTM_WRITE_LOCK_PENDING;
    150 		locked = true;
    151 	} else {
    152 		lock->flags |= TTM_WRITE_LOCK_PENDING;
    153 	}
    154 	spin_unlock(&lock->lock);
    155 	return locked;
    156 }
    157 
    158 int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
    159 {
    160 	int ret = 0;
    161 
    162 	spin_lock(&lock->lock);
    163 	if (interruptible) {
    164 		DRM_SPIN_WAIT_UNTIL(ret, &lock->queue, &lock->lock,
    165 		    __ttm_write_lock(lock));
    166 		if (unlikely(ret != 0)) {
    167 			lock->flags &= ~TTM_WRITE_LOCK_PENDING;
    168 			DRM_SPIN_WAKEUP_ONE(&lock->queue, &lock->lock);
    169 		}
    170 	} else
    171 		DRM_SPIN_WAIT_NOINTR_UNTIL(ret, &lock->queue, &lock->lock,
    172 		    __ttm_write_lock(lock));
    173 	spin_unlock(&lock->lock);
    174 
    175 	return ret;
    176 }
    177 
    178 void ttm_suspend_unlock(struct ttm_lock *lock)
    179 {
    180 	spin_lock(&lock->lock);
    181 	lock->flags &= ~TTM_SUSPEND_LOCK;
    182 	DRM_SPIN_WAKEUP_ALL(&lock->queue, &lock->lock);
    183 	spin_unlock(&lock->lock);
    184 }
    185 
    186 static bool __ttm_suspend_lock(struct ttm_lock *lock)
    187 {
    188 	bool locked = false;
    189 
    190 	if (lock->rw == 0) {
    191 		lock->flags &= ~TTM_SUSPEND_LOCK_PENDING;
    192 		lock->flags |= TTM_SUSPEND_LOCK;
    193 		locked = true;
    194 	} else {
    195 		lock->flags |= TTM_SUSPEND_LOCK_PENDING;
    196 	}
    197 	return locked;
    198 }
    199 
    200 void ttm_suspend_lock(struct ttm_lock *lock)
    201 {
    202 	int ret;
    203 
    204 	spin_lock(&lock->lock);
    205 	DRM_SPIN_WAIT_UNTIL(ret, &lock->queue, &lock->lock,
    206 	    __ttm_suspend_lock(lock));
    207 	spin_unlock(&lock->lock);
    208 }
    209