xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/vmwgfx/ttm_lock.c (revision cae04ea7ef40fb8857bdc41eabe513525bc9f8e8)
1*cae04ea7Sriastradh /*	$NetBSD: ttm_lock.c,v 1.3 2022/02/17 01:21:02 riastradh Exp $	*/
24e390cabSriastradh 
34e390cabSriastradh /* SPDX-License-Identifier: GPL-2.0 OR MIT */
44e390cabSriastradh /**************************************************************************
54e390cabSriastradh  *
64e390cabSriastradh  * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
74e390cabSriastradh  * All Rights Reserved.
84e390cabSriastradh  *
94e390cabSriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
104e390cabSriastradh  * copy of this software and associated documentation files (the
114e390cabSriastradh  * "Software"), to deal in the Software without restriction, including
124e390cabSriastradh  * without limitation the rights to use, copy, modify, merge, publish,
134e390cabSriastradh  * distribute, sub license, and/or sell copies of the Software, and to
144e390cabSriastradh  * permit persons to whom the Software is furnished to do so, subject to
154e390cabSriastradh  * the following conditions:
164e390cabSriastradh  *
174e390cabSriastradh  * The above copyright notice and this permission notice (including the
184e390cabSriastradh  * next paragraph) shall be included in all copies or substantial portions
194e390cabSriastradh  * of the Software.
204e390cabSriastradh  *
214e390cabSriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
224e390cabSriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
234e390cabSriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
244e390cabSriastradh  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
254e390cabSriastradh  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
264e390cabSriastradh  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
274e390cabSriastradh  * USE OR OTHER DEALINGS IN THE SOFTWARE.
284e390cabSriastradh  *
294e390cabSriastradh  **************************************************************************/
304e390cabSriastradh /*
314e390cabSriastradh  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
324e390cabSriastradh  */
334e390cabSriastradh 
344e390cabSriastradh #include <sys/cdefs.h>
35*cae04ea7Sriastradh __KERNEL_RCSID(0, "$NetBSD: ttm_lock.c,v 1.3 2022/02/17 01:21:02 riastradh Exp $");
364e390cabSriastradh 
374e390cabSriastradh #include <linux/atomic.h>
384e390cabSriastradh #include <linux/errno.h>
394e390cabSriastradh #include <linux/wait.h>
404e390cabSriastradh #include <linux/sched/signal.h>
414e390cabSriastradh #include "ttm_lock.h"
424e390cabSriastradh #include "ttm_object.h"
434e390cabSriastradh 
444e390cabSriastradh #define TTM_WRITE_LOCK_PENDING    (1 << 0)
454e390cabSriastradh #define TTM_VT_LOCK_PENDING       (1 << 1)
464e390cabSriastradh #define TTM_SUSPEND_LOCK_PENDING  (1 << 2)
474e390cabSriastradh #define TTM_VT_LOCK               (1 << 3)
484e390cabSriastradh #define TTM_SUSPEND_LOCK          (1 << 4)
494e390cabSriastradh 
ttm_lock_init(struct ttm_lock * lock)504e390cabSriastradh void ttm_lock_init(struct ttm_lock *lock)
514e390cabSriastradh {
524e390cabSriastradh 	spin_lock_init(&lock->lock);
53*cae04ea7Sriastradh 	DRM_INIT_WAITQUEUE(&lock->queue, "ttmlock");
544e390cabSriastradh 	lock->rw = 0;
554e390cabSriastradh 	lock->flags = 0;
564e390cabSriastradh }
574e390cabSriastradh 
ttm_read_unlock(struct ttm_lock * lock)584e390cabSriastradh void ttm_read_unlock(struct ttm_lock *lock)
594e390cabSriastradh {
604e390cabSriastradh 	spin_lock(&lock->lock);
614e390cabSriastradh 	if (--lock->rw == 0)
62*cae04ea7Sriastradh 		DRM_SPIN_WAKEUP_ALL(&lock->queue, &lock->lock);
634e390cabSriastradh 	spin_unlock(&lock->lock);
644e390cabSriastradh }
654e390cabSriastradh 
__ttm_read_lock(struct ttm_lock * lock)664e390cabSriastradh static bool __ttm_read_lock(struct ttm_lock *lock)
674e390cabSriastradh {
684e390cabSriastradh 	bool locked = false;
694e390cabSriastradh 
704e390cabSriastradh 	if (lock->rw >= 0 && lock->flags == 0) {
714e390cabSriastradh 		++lock->rw;
724e390cabSriastradh 		locked = true;
734e390cabSriastradh 	}
744e390cabSriastradh 	return locked;
754e390cabSriastradh }
764e390cabSriastradh 
ttm_read_lock(struct ttm_lock * lock,bool interruptible)774e390cabSriastradh int ttm_read_lock(struct ttm_lock *lock, bool interruptible)
784e390cabSriastradh {
794e390cabSriastradh 	int ret = 0;
804e390cabSriastradh 
81*cae04ea7Sriastradh 	spin_lock(&lock->lock);
824e390cabSriastradh 	if (interruptible)
83*cae04ea7Sriastradh 		DRM_SPIN_WAIT_UNTIL(ret, &lock->queue, &lock->lock,
844e390cabSriastradh 		    __ttm_read_lock(lock));
854e390cabSriastradh 	else
86*cae04ea7Sriastradh 		DRM_SPIN_WAIT_NOINTR_UNTIL(ret, &lock->queue, &lock->lock,
87*cae04ea7Sriastradh 		    __ttm_read_lock(lock));
88*cae04ea7Sriastradh 	spin_unlock(&lock->lock);
89*cae04ea7Sriastradh 
904e390cabSriastradh 	return ret;
914e390cabSriastradh }
924e390cabSriastradh 
__ttm_read_trylock(struct ttm_lock * lock,bool * locked)934e390cabSriastradh static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked)
944e390cabSriastradh {
954e390cabSriastradh 	bool block = true;
964e390cabSriastradh 
974e390cabSriastradh 	*locked = false;
984e390cabSriastradh 
994e390cabSriastradh 	spin_lock(&lock->lock);
1004e390cabSriastradh 	if (lock->rw >= 0 && lock->flags == 0) {
1014e390cabSriastradh 		++lock->rw;
1024e390cabSriastradh 		block = false;
1034e390cabSriastradh 		*locked = true;
1044e390cabSriastradh 	} else if (lock->flags == 0) {
1054e390cabSriastradh 		block = false;
1064e390cabSriastradh 	}
1074e390cabSriastradh 	spin_unlock(&lock->lock);
1084e390cabSriastradh 
1094e390cabSriastradh 	return !block;
1104e390cabSriastradh }
1114e390cabSriastradh 
ttm_read_trylock(struct ttm_lock * lock,bool interruptible)1124e390cabSriastradh int ttm_read_trylock(struct ttm_lock *lock, bool interruptible)
1134e390cabSriastradh {
1144e390cabSriastradh 	int ret = 0;
1154e390cabSriastradh 	bool locked;
1164e390cabSriastradh 
117*cae04ea7Sriastradh 	spin_lock(&lock->lock);
1184e390cabSriastradh 	if (interruptible)
119*cae04ea7Sriastradh 		DRM_SPIN_WAIT_UNTIL(ret, &lock->queue, &lock->lock,
120*cae04ea7Sriastradh 		    __ttm_read_trylock(lock, &locked));
1214e390cabSriastradh 	else
122*cae04ea7Sriastradh 		DRM_SPIN_WAIT_NOINTR_UNTIL(ret, &lock->queue, &lock->lock,
123*cae04ea7Sriastradh 		    __ttm_read_trylock(lock, &locked));
124*cae04ea7Sriastradh 	spin_unlock(&lock->lock);
1254e390cabSriastradh 
1264e390cabSriastradh 	if (unlikely(ret != 0)) {
1274e390cabSriastradh 		BUG_ON(locked);
1284e390cabSriastradh 		return ret;
1294e390cabSriastradh 	}
1304e390cabSriastradh 
1314e390cabSriastradh 	return (locked) ? 0 : -EBUSY;
1324e390cabSriastradh }
1334e390cabSriastradh 
ttm_write_unlock(struct ttm_lock * lock)1344e390cabSriastradh void ttm_write_unlock(struct ttm_lock *lock)
1354e390cabSriastradh {
1364e390cabSriastradh 	spin_lock(&lock->lock);
1374e390cabSriastradh 	lock->rw = 0;
138*cae04ea7Sriastradh 	DRM_SPIN_WAKEUP_ALL(&lock->queue, &lock->lock);
1394e390cabSriastradh 	spin_unlock(&lock->lock);
1404e390cabSriastradh }
1414e390cabSriastradh 
__ttm_write_lock(struct ttm_lock * lock)1424e390cabSriastradh static bool __ttm_write_lock(struct ttm_lock *lock)
1434e390cabSriastradh {
1444e390cabSriastradh 	bool locked = false;
1454e390cabSriastradh 
1464e390cabSriastradh 	spin_lock(&lock->lock);
1474e390cabSriastradh 	if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) {
1484e390cabSriastradh 		lock->rw = -1;
1494e390cabSriastradh 		lock->flags &= ~TTM_WRITE_LOCK_PENDING;
1504e390cabSriastradh 		locked = true;
1514e390cabSriastradh 	} else {
1524e390cabSriastradh 		lock->flags |= TTM_WRITE_LOCK_PENDING;
1534e390cabSriastradh 	}
1544e390cabSriastradh 	spin_unlock(&lock->lock);
1554e390cabSriastradh 	return locked;
1564e390cabSriastradh }
1574e390cabSriastradh 
ttm_write_lock(struct ttm_lock * lock,bool interruptible)1584e390cabSriastradh int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
1594e390cabSriastradh {
1604e390cabSriastradh 	int ret = 0;
1614e390cabSriastradh 
162*cae04ea7Sriastradh 	spin_lock(&lock->lock);
1634e390cabSriastradh 	if (interruptible) {
164*cae04ea7Sriastradh 		DRM_SPIN_WAIT_UNTIL(ret, &lock->queue, &lock->lock,
1654e390cabSriastradh 		    __ttm_write_lock(lock));
1664e390cabSriastradh 		if (unlikely(ret != 0)) {
1674e390cabSriastradh 			lock->flags &= ~TTM_WRITE_LOCK_PENDING;
168*cae04ea7Sriastradh 			DRM_SPIN_WAKEUP_ONE(&lock->queue, &lock->lock);
1694e390cabSriastradh 		}
1704e390cabSriastradh 	} else
171*cae04ea7Sriastradh 		DRM_SPIN_WAIT_NOINTR_UNTIL(ret, &lock->queue, &lock->lock,
172*cae04ea7Sriastradh 		    __ttm_write_lock(lock));
173*cae04ea7Sriastradh 	spin_unlock(&lock->lock);
1744e390cabSriastradh 
1754e390cabSriastradh 	return ret;
1764e390cabSriastradh }
1774e390cabSriastradh 
ttm_suspend_unlock(struct ttm_lock * lock)1784e390cabSriastradh void ttm_suspend_unlock(struct ttm_lock *lock)
1794e390cabSriastradh {
1804e390cabSriastradh 	spin_lock(&lock->lock);
1814e390cabSriastradh 	lock->flags &= ~TTM_SUSPEND_LOCK;
182*cae04ea7Sriastradh 	DRM_SPIN_WAKEUP_ALL(&lock->queue, &lock->lock);
1834e390cabSriastradh 	spin_unlock(&lock->lock);
1844e390cabSriastradh }
1854e390cabSriastradh 
__ttm_suspend_lock(struct ttm_lock * lock)1864e390cabSriastradh static bool __ttm_suspend_lock(struct ttm_lock *lock)
1874e390cabSriastradh {
1884e390cabSriastradh 	bool locked = false;
1894e390cabSriastradh 
1904e390cabSriastradh 	if (lock->rw == 0) {
1914e390cabSriastradh 		lock->flags &= ~TTM_SUSPEND_LOCK_PENDING;
1924e390cabSriastradh 		lock->flags |= TTM_SUSPEND_LOCK;
1934e390cabSriastradh 		locked = true;
1944e390cabSriastradh 	} else {
1954e390cabSriastradh 		lock->flags |= TTM_SUSPEND_LOCK_PENDING;
1964e390cabSriastradh 	}
1974e390cabSriastradh 	return locked;
1984e390cabSriastradh }
1994e390cabSriastradh 
ttm_suspend_lock(struct ttm_lock * lock)2004e390cabSriastradh void ttm_suspend_lock(struct ttm_lock *lock)
2014e390cabSriastradh {
202*cae04ea7Sriastradh 	int ret;
203*cae04ea7Sriastradh 
204*cae04ea7Sriastradh 	spin_lock(&lock->lock);
205*cae04ea7Sriastradh 	DRM_SPIN_WAIT_UNTIL(ret, &lock->queue, &lock->lock,
206*cae04ea7Sriastradh 	    __ttm_suspend_lock(lock));
207*cae04ea7Sriastradh 	spin_unlock(&lock->lock);
2084e390cabSriastradh }
209