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