151f49692SMarouene Boubakri /* SPDX-License-Identifier: BSD-2-Clause */
251f49692SMarouene Boubakri /*
351f49692SMarouene Boubakri * Copyright (c) 2014-2017, Linaro Limited
451f49692SMarouene Boubakri */
5d50fee03SEtienne Carriere #ifndef __KERNEL_MUTEX_H
6d50fee03SEtienne Carriere #define __KERNEL_MUTEX_H
751f49692SMarouene Boubakri
851f49692SMarouene Boubakri #include <kernel/refcount.h>
951f49692SMarouene Boubakri #include <kernel/wait_queue.h>
1051f49692SMarouene Boubakri #include <sys/queue.h>
1151f49692SMarouene Boubakri #include <types_ext.h>
1251f49692SMarouene Boubakri
1351f49692SMarouene Boubakri struct mutex {
1451f49692SMarouene Boubakri unsigned spin_lock; /* used when operating on this struct */
1551f49692SMarouene Boubakri struct wait_queue wq;
1651f49692SMarouene Boubakri short state; /* -1: write, 0: unlocked, > 0: readers */
1751f49692SMarouene Boubakri };
1851f49692SMarouene Boubakri
1951f49692SMarouene Boubakri #define MUTEX_INITIALIZER { .wq = WAIT_QUEUE_INITIALIZER }
2051f49692SMarouene Boubakri
2151f49692SMarouene Boubakri struct recursive_mutex {
2251f49692SMarouene Boubakri struct mutex m; /* used when lock_depth goes 0 -> 1 or 1 -> 0 */
2351f49692SMarouene Boubakri short int owner;
2451f49692SMarouene Boubakri struct refcount lock_depth;
2551f49692SMarouene Boubakri };
2651f49692SMarouene Boubakri
2751f49692SMarouene Boubakri #define RECURSIVE_MUTEX_INITIALIZER { .m = MUTEX_INITIALIZER, \
2851f49692SMarouene Boubakri .owner = THREAD_ID_INVALID }
2951f49692SMarouene Boubakri
3051f49692SMarouene Boubakri TAILQ_HEAD(mutex_head, mutex);
3151f49692SMarouene Boubakri
3251f49692SMarouene Boubakri void mutex_init(struct mutex *m);
3351f49692SMarouene Boubakri void mutex_destroy(struct mutex *m);
3451f49692SMarouene Boubakri
3551f49692SMarouene Boubakri void mutex_init_recursive(struct recursive_mutex *m);
3651f49692SMarouene Boubakri void mutex_destroy_recursive(struct recursive_mutex *m);
3751f49692SMarouene Boubakri unsigned int mutex_get_recursive_lock_depth(struct recursive_mutex *m);
3851f49692SMarouene Boubakri
3951f49692SMarouene Boubakri #ifdef CFG_MUTEX_DEBUG
4051f49692SMarouene Boubakri void mutex_unlock_debug(struct mutex *m, const char *fname, int lineno);
4151f49692SMarouene Boubakri #define mutex_unlock(m) mutex_unlock_debug((m), __FILE__, __LINE__)
4251f49692SMarouene Boubakri
4351f49692SMarouene Boubakri void mutex_lock_debug(struct mutex *m, const char *fname, int lineno);
4451f49692SMarouene Boubakri #define mutex_lock(m) mutex_lock_debug((m), __FILE__, __LINE__)
4551f49692SMarouene Boubakri
4651f49692SMarouene Boubakri bool mutex_trylock_debug(struct mutex *m, const char *fname, int lineno);
4751f49692SMarouene Boubakri #define mutex_trylock(m) mutex_trylock_debug((m), __FILE__, __LINE__)
4851f49692SMarouene Boubakri
4951f49692SMarouene Boubakri void mutex_read_unlock_debug(struct mutex *m, const char *fname, int lineno);
5051f49692SMarouene Boubakri #define mutex_read_unlock(m) mutex_read_unlock_debug((m), __FILE__, __LINE__)
5151f49692SMarouene Boubakri
5251f49692SMarouene Boubakri void mutex_read_lock_debug(struct mutex *m, const char *fname, int lineno);
5351f49692SMarouene Boubakri #define mutex_read_lock(m) mutex_read_lock_debug((m), __FILE__, __LINE__)
5451f49692SMarouene Boubakri
5551f49692SMarouene Boubakri bool mutex_read_trylock_debug(struct mutex *m, const char *fname, int lineno);
5651f49692SMarouene Boubakri #define mutex_read_trylock(m) mutex_read_trylock_debug((m), __FILE__, __LINE__)
5751f49692SMarouene Boubakri
5851f49692SMarouene Boubakri void mutex_unlock_recursive_debug(struct recursive_mutex *m, const char *fname,
5951f49692SMarouene Boubakri int lineno);
6051f49692SMarouene Boubakri #define mutex_unlock_recursive(m) mutex_unlock_recursive_debug((m), __FILE__, \
6151f49692SMarouene Boubakri __LINE__)
6251f49692SMarouene Boubakri
6351f49692SMarouene Boubakri void mutex_lock_recursive_debug(struct recursive_mutex *m, const char *fname,
6451f49692SMarouene Boubakri int lineno);
6551f49692SMarouene Boubakri #define mutex_lock_recursive(m) mutex_lock_recursive_debug((m), __FILE__, \
6651f49692SMarouene Boubakri __LINE__)
6751f49692SMarouene Boubakri #else
6851f49692SMarouene Boubakri void mutex_unlock(struct mutex *m);
6951f49692SMarouene Boubakri void mutex_lock(struct mutex *m);
7051f49692SMarouene Boubakri bool mutex_trylock(struct mutex *m);
7151f49692SMarouene Boubakri void mutex_read_unlock(struct mutex *m);
7251f49692SMarouene Boubakri void mutex_read_lock(struct mutex *m);
7351f49692SMarouene Boubakri bool mutex_read_trylock(struct mutex *m);
7451f49692SMarouene Boubakri
7551f49692SMarouene Boubakri void mutex_unlock_recursive(struct recursive_mutex *m);
7651f49692SMarouene Boubakri void mutex_lock_recursive(struct recursive_mutex *m);
7751f49692SMarouene Boubakri #endif
7851f49692SMarouene Boubakri
7951f49692SMarouene Boubakri struct condvar {
807921973cSEtienne Carriere unsigned int spin_lock;
8151f49692SMarouene Boubakri struct mutex *m;
8251f49692SMarouene Boubakri };
8351f49692SMarouene Boubakri #define CONDVAR_INITIALIZER { .m = NULL }
8451f49692SMarouene Boubakri
8551f49692SMarouene Boubakri void condvar_init(struct condvar *cv);
8651f49692SMarouene Boubakri void condvar_destroy(struct condvar *cv);
8751f49692SMarouene Boubakri
8851f49692SMarouene Boubakri #ifdef CFG_MUTEX_DEBUG
8951f49692SMarouene Boubakri void condvar_signal_debug(struct condvar *cv, const char *fname, int lineno);
9051f49692SMarouene Boubakri #define condvar_signal(cv) condvar_signal_debug((cv), __FILE__, __LINE__)
9151f49692SMarouene Boubakri
9251f49692SMarouene Boubakri void condvar_broadcast_debug(struct condvar *cv, const char *fname, int lineno);
9351f49692SMarouene Boubakri #define condvar_broadcast(cv) condvar_broadcast_debug((cv), __FILE__, __LINE__)
9451f49692SMarouene Boubakri
9551f49692SMarouene Boubakri void condvar_wait_debug(struct condvar *cv, struct mutex *m,
9651f49692SMarouene Boubakri const char *fname, int lineno);
9751f49692SMarouene Boubakri #define condvar_wait(cv, m) condvar_wait_debug((cv), (m), __FILE__, __LINE__)
98ea413ca5SGavin Liu
99ea413ca5SGavin Liu /*
100ea413ca5SGavin Liu * Return TEE_ERROR_TIMEOUT if the normal world returns before
101ea413ca5SGavin Liu * the condvar has been signaled.
102ea413ca5SGavin Liu */
103ea413ca5SGavin Liu TEE_Result condvar_wait_timeout_debug(struct condvar *cv, struct mutex *m,
104ea413ca5SGavin Liu uint32_t timeout_ms, const char *fname,
105ea413ca5SGavin Liu int lineno);
106ea413ca5SGavin Liu #define condvar_wait_timeout(cv, m, timeout_ms) \
107ea413ca5SGavin Liu condvar_wait_timeout_debug((cv), (m), (timeout_ms), __FILE__, __LINE__)
10851f49692SMarouene Boubakri #else
10951f49692SMarouene Boubakri void condvar_signal(struct condvar *cv);
11051f49692SMarouene Boubakri void condvar_broadcast(struct condvar *cv);
11151f49692SMarouene Boubakri void condvar_wait(struct condvar *cv, struct mutex *m);
112ea413ca5SGavin Liu /*
113ea413ca5SGavin Liu * Return TEE_ERROR_TIMEOUT if the normal world returns before
114ea413ca5SGavin Liu * the condvar has been signaled.
115ea413ca5SGavin Liu */
116ea413ca5SGavin Liu TEE_Result condvar_wait_timeout(struct condvar *cv, struct mutex *m,
117ea413ca5SGavin Liu uint32_t timeout_ms);
11851f49692SMarouene Boubakri #endif
11951f49692SMarouene Boubakri
12030730d67SEtienne Carriere /*
121*956c2d50SEtienne Carriere * Helper for testing that a given mutex is locked for writing. This helper
122*956c2d50SEtienne Carriere * is to be used with caution since it does not guarantee that the executing
123*956c2d50SEtienne Carriere * thread is holding the mutex.
12430730d67SEtienne Carriere */
mutex_is_locked(struct mutex * m)12530730d67SEtienne Carriere static inline bool mutex_is_locked(struct mutex *m)
12630730d67SEtienne Carriere {
127*956c2d50SEtienne Carriere return m->state == -1; /* write locked */
12830730d67SEtienne Carriere }
129d50fee03SEtienne Carriere #endif /*__KERNEL_MUTEX_H*/
13051f49692SMarouene Boubakri
131