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