151f49692SMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause
251f49692SMarouene Boubakri /*
351f49692SMarouene Boubakri * Copyright (c) 2015-2017, Linaro Limited
451f49692SMarouene Boubakri */
551f49692SMarouene Boubakri
651f49692SMarouene Boubakri #include <kernel/mutex.h>
73a20c661SEtienne Carriere #include <kernel/mutex_pm_aware.h>
851f49692SMarouene Boubakri #include <kernel/panic.h>
951f49692SMarouene Boubakri #include <kernel/refcount.h>
1051f49692SMarouene Boubakri #include <kernel/spinlock.h>
1151f49692SMarouene Boubakri #include <kernel/thread.h>
1251f49692SMarouene Boubakri #include <trace.h>
1351f49692SMarouene Boubakri
1451f49692SMarouene Boubakri #include "mutex_lockdep.h"
1551f49692SMarouene Boubakri
mutex_init(struct mutex * m)1651f49692SMarouene Boubakri void mutex_init(struct mutex *m)
1751f49692SMarouene Boubakri {
1851f49692SMarouene Boubakri *m = (struct mutex)MUTEX_INITIALIZER;
1951f49692SMarouene Boubakri }
2051f49692SMarouene Boubakri
mutex_init_recursive(struct recursive_mutex * m)2151f49692SMarouene Boubakri void mutex_init_recursive(struct recursive_mutex *m)
2251f49692SMarouene Boubakri {
2351f49692SMarouene Boubakri *m = (struct recursive_mutex)RECURSIVE_MUTEX_INITIALIZER;
2451f49692SMarouene Boubakri }
2551f49692SMarouene Boubakri
__mutex_lock(struct mutex * m,const char * fname,int lineno)2651f49692SMarouene Boubakri static void __mutex_lock(struct mutex *m, const char *fname, int lineno)
2751f49692SMarouene Boubakri {
2851f49692SMarouene Boubakri assert_have_no_spinlock();
2951f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID);
3051f49692SMarouene Boubakri assert(thread_is_in_normal_mode());
3151f49692SMarouene Boubakri
3251f49692SMarouene Boubakri mutex_lock_check(m);
3351f49692SMarouene Boubakri
3451f49692SMarouene Boubakri while (true) {
3551f49692SMarouene Boubakri uint32_t old_itr_status;
3651f49692SMarouene Boubakri bool can_lock;
3751f49692SMarouene Boubakri struct wait_queue_elem wqe;
3851f49692SMarouene Boubakri
3951f49692SMarouene Boubakri /*
4051f49692SMarouene Boubakri * If the mutex is locked we need to initialize the wqe
4151f49692SMarouene Boubakri * before releasing the spinlock to guarantee that we don't
4251f49692SMarouene Boubakri * miss the wakeup from mutex_unlock().
4351f49692SMarouene Boubakri *
4451f49692SMarouene Boubakri * If the mutex is unlocked we don't need to use the wqe at
4551f49692SMarouene Boubakri * all.
4651f49692SMarouene Boubakri */
4751f49692SMarouene Boubakri
4851f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock);
4951f49692SMarouene Boubakri
5051f49692SMarouene Boubakri can_lock = !m->state;
5151f49692SMarouene Boubakri if (!can_lock) {
5251f49692SMarouene Boubakri wq_wait_init(&m->wq, &wqe, false /* wait_read */);
5351f49692SMarouene Boubakri } else {
5451f49692SMarouene Boubakri m->state = -1; /* write locked */
5551f49692SMarouene Boubakri }
5651f49692SMarouene Boubakri
5751f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status);
5851f49692SMarouene Boubakri
5951f49692SMarouene Boubakri if (!can_lock) {
6051f49692SMarouene Boubakri /*
6151f49692SMarouene Boubakri * Someone else is holding the lock, wait in normal
6251f49692SMarouene Boubakri * world for the lock to become available.
6351f49692SMarouene Boubakri */
64*ea413ca5SGavin Liu wq_wait_final(&m->wq, &wqe, 0, m, fname, lineno);
6551f49692SMarouene Boubakri } else
6651f49692SMarouene Boubakri return;
6751f49692SMarouene Boubakri }
6851f49692SMarouene Boubakri }
6951f49692SMarouene Boubakri
__mutex_lock_recursive(struct recursive_mutex * m,const char * fname,int lineno)7051f49692SMarouene Boubakri static void __mutex_lock_recursive(struct recursive_mutex *m, const char *fname,
7151f49692SMarouene Boubakri int lineno)
7251f49692SMarouene Boubakri {
7351f49692SMarouene Boubakri short int ct = thread_get_id();
7451f49692SMarouene Boubakri
7551f49692SMarouene Boubakri assert_have_no_spinlock();
7651f49692SMarouene Boubakri assert(thread_is_in_normal_mode());
7751f49692SMarouene Boubakri
7851f49692SMarouene Boubakri if (atomic_load_short(&m->owner) == ct) {
7951f49692SMarouene Boubakri if (!refcount_inc(&m->lock_depth))
8051f49692SMarouene Boubakri panic();
8151f49692SMarouene Boubakri return;
8251f49692SMarouene Boubakri }
8351f49692SMarouene Boubakri
8451f49692SMarouene Boubakri __mutex_lock(&m->m, fname, lineno);
8551f49692SMarouene Boubakri
8651f49692SMarouene Boubakri assert(m->owner == THREAD_ID_INVALID);
8751f49692SMarouene Boubakri atomic_store_short(&m->owner, ct);
8851f49692SMarouene Boubakri refcount_set(&m->lock_depth, 1);
8951f49692SMarouene Boubakri }
9051f49692SMarouene Boubakri
__mutex_unlock(struct mutex * m,const char * fname,int lineno)9151f49692SMarouene Boubakri static void __mutex_unlock(struct mutex *m, const char *fname, int lineno)
9251f49692SMarouene Boubakri {
9351f49692SMarouene Boubakri uint32_t old_itr_status;
9451f49692SMarouene Boubakri
9551f49692SMarouene Boubakri assert_have_no_spinlock();
9651f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID);
9751f49692SMarouene Boubakri
9851f49692SMarouene Boubakri mutex_unlock_check(m);
9951f49692SMarouene Boubakri
10051f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock);
10151f49692SMarouene Boubakri
10251f49692SMarouene Boubakri if (!m->state)
10351f49692SMarouene Boubakri panic();
10451f49692SMarouene Boubakri
10551f49692SMarouene Boubakri m->state = 0;
10651f49692SMarouene Boubakri
10751f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status);
10851f49692SMarouene Boubakri
10951f49692SMarouene Boubakri wq_wake_next(&m->wq, m, fname, lineno);
11051f49692SMarouene Boubakri }
11151f49692SMarouene Boubakri
__mutex_unlock_recursive(struct recursive_mutex * m,const char * fname,int lineno)11251f49692SMarouene Boubakri static void __mutex_unlock_recursive(struct recursive_mutex *m,
11351f49692SMarouene Boubakri const char *fname, int lineno)
11451f49692SMarouene Boubakri {
11551f49692SMarouene Boubakri assert_have_no_spinlock();
11651f49692SMarouene Boubakri assert(m->owner == thread_get_id());
11751f49692SMarouene Boubakri
11851f49692SMarouene Boubakri if (refcount_dec(&m->lock_depth)) {
11951f49692SMarouene Boubakri /*
12051f49692SMarouene Boubakri * Do an atomic store to match the atomic load in
12151f49692SMarouene Boubakri * __mutex_lock_recursive()
12251f49692SMarouene Boubakri */
12351f49692SMarouene Boubakri atomic_store_short(&m->owner, THREAD_ID_INVALID);
12451f49692SMarouene Boubakri __mutex_unlock(&m->m, fname, lineno);
12551f49692SMarouene Boubakri }
12651f49692SMarouene Boubakri }
12751f49692SMarouene Boubakri
__mutex_trylock(struct mutex * m,const char * fname __unused,int lineno __unused)12851f49692SMarouene Boubakri static bool __mutex_trylock(struct mutex *m, const char *fname __unused,
12951f49692SMarouene Boubakri int lineno __unused)
13051f49692SMarouene Boubakri {
13151f49692SMarouene Boubakri uint32_t old_itr_status;
13251f49692SMarouene Boubakri bool can_lock_write;
13351f49692SMarouene Boubakri
13451f49692SMarouene Boubakri assert_have_no_spinlock();
13551f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID);
13651f49692SMarouene Boubakri
13751f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock);
13851f49692SMarouene Boubakri
13951f49692SMarouene Boubakri can_lock_write = !m->state;
14051f49692SMarouene Boubakri if (can_lock_write)
14151f49692SMarouene Boubakri m->state = -1;
14251f49692SMarouene Boubakri
14351f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status);
14451f49692SMarouene Boubakri
14551f49692SMarouene Boubakri if (can_lock_write)
14651f49692SMarouene Boubakri mutex_trylock_check(m);
14751f49692SMarouene Boubakri
14851f49692SMarouene Boubakri return can_lock_write;
14951f49692SMarouene Boubakri }
15051f49692SMarouene Boubakri
__mutex_read_unlock(struct mutex * m,const char * fname,int lineno)15151f49692SMarouene Boubakri static void __mutex_read_unlock(struct mutex *m, const char *fname, int lineno)
15251f49692SMarouene Boubakri {
15351f49692SMarouene Boubakri uint32_t old_itr_status;
15451f49692SMarouene Boubakri short new_state;
15551f49692SMarouene Boubakri
15651f49692SMarouene Boubakri assert_have_no_spinlock();
15751f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID);
15851f49692SMarouene Boubakri
15951f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock);
16051f49692SMarouene Boubakri
16151f49692SMarouene Boubakri if (m->state <= 0)
16251f49692SMarouene Boubakri panic();
16351f49692SMarouene Boubakri m->state--;
16451f49692SMarouene Boubakri new_state = m->state;
16551f49692SMarouene Boubakri
16651f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status);
16751f49692SMarouene Boubakri
16851f49692SMarouene Boubakri /* Wake eventual waiters if the mutex was unlocked */
16951f49692SMarouene Boubakri if (!new_state)
17051f49692SMarouene Boubakri wq_wake_next(&m->wq, m, fname, lineno);
17151f49692SMarouene Boubakri }
17251f49692SMarouene Boubakri
__mutex_read_lock(struct mutex * m,const char * fname,int lineno)17351f49692SMarouene Boubakri static void __mutex_read_lock(struct mutex *m, const char *fname, int lineno)
17451f49692SMarouene Boubakri {
17551f49692SMarouene Boubakri assert_have_no_spinlock();
17651f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID);
17751f49692SMarouene Boubakri assert(thread_is_in_normal_mode());
17851f49692SMarouene Boubakri
17951f49692SMarouene Boubakri while (true) {
18051f49692SMarouene Boubakri uint32_t old_itr_status;
18151f49692SMarouene Boubakri bool can_lock;
18251f49692SMarouene Boubakri struct wait_queue_elem wqe;
18351f49692SMarouene Boubakri
18451f49692SMarouene Boubakri /*
18551f49692SMarouene Boubakri * If the mutex is locked we need to initialize the wqe
18651f49692SMarouene Boubakri * before releasing the spinlock to guarantee that we don't
18751f49692SMarouene Boubakri * miss the wakeup from mutex_unlock().
18851f49692SMarouene Boubakri *
18951f49692SMarouene Boubakri * If the mutex is unlocked we don't need to use the wqe at
19051f49692SMarouene Boubakri * all.
19151f49692SMarouene Boubakri */
19251f49692SMarouene Boubakri
19351f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock);
19451f49692SMarouene Boubakri
19551f49692SMarouene Boubakri can_lock = m->state != -1;
19651f49692SMarouene Boubakri if (!can_lock) {
19751f49692SMarouene Boubakri wq_wait_init(&m->wq, &wqe, true /* wait_read */);
19851f49692SMarouene Boubakri } else {
19951f49692SMarouene Boubakri m->state++; /* read_locked */
20051f49692SMarouene Boubakri }
20151f49692SMarouene Boubakri
20251f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status);
20351f49692SMarouene Boubakri
20451f49692SMarouene Boubakri if (!can_lock) {
20551f49692SMarouene Boubakri /*
20651f49692SMarouene Boubakri * Someone else is holding the lock, wait in normal
20751f49692SMarouene Boubakri * world for the lock to become available.
20851f49692SMarouene Boubakri */
209*ea413ca5SGavin Liu wq_wait_final(&m->wq, &wqe, 0, m, fname, lineno);
21051f49692SMarouene Boubakri } else
21151f49692SMarouene Boubakri return;
21251f49692SMarouene Boubakri }
21351f49692SMarouene Boubakri }
21451f49692SMarouene Boubakri
__mutex_read_trylock(struct mutex * m,const char * fname __unused,int lineno __unused)21551f49692SMarouene Boubakri static bool __mutex_read_trylock(struct mutex *m, const char *fname __unused,
21651f49692SMarouene Boubakri int lineno __unused)
21751f49692SMarouene Boubakri {
21851f49692SMarouene Boubakri uint32_t old_itr_status;
21951f49692SMarouene Boubakri bool can_lock;
22051f49692SMarouene Boubakri
22151f49692SMarouene Boubakri assert_have_no_spinlock();
22251f49692SMarouene Boubakri assert(thread_get_id_may_fail() != THREAD_ID_INVALID);
22351f49692SMarouene Boubakri assert(thread_is_in_normal_mode());
22451f49692SMarouene Boubakri
22551f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&m->spin_lock);
22651f49692SMarouene Boubakri
22751f49692SMarouene Boubakri can_lock = m->state != -1;
22851f49692SMarouene Boubakri if (can_lock)
22951f49692SMarouene Boubakri m->state++;
23051f49692SMarouene Boubakri
23151f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status);
23251f49692SMarouene Boubakri
23351f49692SMarouene Boubakri return can_lock;
23451f49692SMarouene Boubakri }
23551f49692SMarouene Boubakri
23651f49692SMarouene Boubakri #ifdef CFG_MUTEX_DEBUG
mutex_unlock_debug(struct mutex * m,const char * fname,int lineno)23751f49692SMarouene Boubakri void mutex_unlock_debug(struct mutex *m, const char *fname, int lineno)
23851f49692SMarouene Boubakri {
23951f49692SMarouene Boubakri __mutex_unlock(m, fname, lineno);
24051f49692SMarouene Boubakri }
24151f49692SMarouene Boubakri
mutex_lock_debug(struct mutex * m,const char * fname,int lineno)24251f49692SMarouene Boubakri void mutex_lock_debug(struct mutex *m, const char *fname, int lineno)
24351f49692SMarouene Boubakri {
24451f49692SMarouene Boubakri __mutex_lock(m, fname, lineno);
24551f49692SMarouene Boubakri }
24651f49692SMarouene Boubakri
mutex_trylock_debug(struct mutex * m,const char * fname,int lineno)24751f49692SMarouene Boubakri bool mutex_trylock_debug(struct mutex *m, const char *fname, int lineno)
24851f49692SMarouene Boubakri {
24951f49692SMarouene Boubakri return __mutex_trylock(m, fname, lineno);
25051f49692SMarouene Boubakri }
25151f49692SMarouene Boubakri
mutex_read_unlock_debug(struct mutex * m,const char * fname,int lineno)25251f49692SMarouene Boubakri void mutex_read_unlock_debug(struct mutex *m, const char *fname, int lineno)
25351f49692SMarouene Boubakri {
25451f49692SMarouene Boubakri __mutex_read_unlock(m, fname, lineno);
25551f49692SMarouene Boubakri }
25651f49692SMarouene Boubakri
mutex_read_lock_debug(struct mutex * m,const char * fname,int lineno)25751f49692SMarouene Boubakri void mutex_read_lock_debug(struct mutex *m, const char *fname, int lineno)
25851f49692SMarouene Boubakri {
25951f49692SMarouene Boubakri __mutex_read_lock(m, fname, lineno);
26051f49692SMarouene Boubakri }
26151f49692SMarouene Boubakri
mutex_read_trylock_debug(struct mutex * m,const char * fname,int lineno)26251f49692SMarouene Boubakri bool mutex_read_trylock_debug(struct mutex *m, const char *fname, int lineno)
26351f49692SMarouene Boubakri {
26451f49692SMarouene Boubakri return __mutex_read_trylock(m, fname, lineno);
26551f49692SMarouene Boubakri }
26651f49692SMarouene Boubakri
mutex_unlock_recursive_debug(struct recursive_mutex * m,const char * fname,int lineno)26751f49692SMarouene Boubakri void mutex_unlock_recursive_debug(struct recursive_mutex *m, const char *fname,
26851f49692SMarouene Boubakri int lineno)
26951f49692SMarouene Boubakri {
27051f49692SMarouene Boubakri __mutex_unlock_recursive(m, fname, lineno);
27151f49692SMarouene Boubakri }
27251f49692SMarouene Boubakri
mutex_lock_recursive_debug(struct recursive_mutex * m,const char * fname,int lineno)27351f49692SMarouene Boubakri void mutex_lock_recursive_debug(struct recursive_mutex *m, const char *fname,
27451f49692SMarouene Boubakri int lineno)
27551f49692SMarouene Boubakri {
27651f49692SMarouene Boubakri __mutex_lock_recursive(m, fname, lineno);
27751f49692SMarouene Boubakri }
27851f49692SMarouene Boubakri #else
mutex_unlock(struct mutex * m)27951f49692SMarouene Boubakri void mutex_unlock(struct mutex *m)
28051f49692SMarouene Boubakri {
28151f49692SMarouene Boubakri __mutex_unlock(m, NULL, -1);
28251f49692SMarouene Boubakri }
28351f49692SMarouene Boubakri
mutex_unlock_recursive(struct recursive_mutex * m)28451f49692SMarouene Boubakri void mutex_unlock_recursive(struct recursive_mutex *m)
28551f49692SMarouene Boubakri {
28651f49692SMarouene Boubakri __mutex_unlock_recursive(m, NULL, -1);
28751f49692SMarouene Boubakri }
28851f49692SMarouene Boubakri
mutex_lock(struct mutex * m)28951f49692SMarouene Boubakri void mutex_lock(struct mutex *m)
29051f49692SMarouene Boubakri {
29151f49692SMarouene Boubakri __mutex_lock(m, NULL, -1);
29251f49692SMarouene Boubakri }
29351f49692SMarouene Boubakri
mutex_lock_recursive(struct recursive_mutex * m)29451f49692SMarouene Boubakri void mutex_lock_recursive(struct recursive_mutex *m)
29551f49692SMarouene Boubakri {
29651f49692SMarouene Boubakri __mutex_lock_recursive(m, NULL, -1);
29751f49692SMarouene Boubakri }
29851f49692SMarouene Boubakri
mutex_trylock(struct mutex * m)29951f49692SMarouene Boubakri bool mutex_trylock(struct mutex *m)
30051f49692SMarouene Boubakri {
30151f49692SMarouene Boubakri return __mutex_trylock(m, NULL, -1);
30251f49692SMarouene Boubakri }
30351f49692SMarouene Boubakri
mutex_read_unlock(struct mutex * m)30451f49692SMarouene Boubakri void mutex_read_unlock(struct mutex *m)
30551f49692SMarouene Boubakri {
30651f49692SMarouene Boubakri __mutex_read_unlock(m, NULL, -1);
30751f49692SMarouene Boubakri }
30851f49692SMarouene Boubakri
mutex_read_lock(struct mutex * m)30951f49692SMarouene Boubakri void mutex_read_lock(struct mutex *m)
31051f49692SMarouene Boubakri {
31151f49692SMarouene Boubakri __mutex_read_lock(m, NULL, -1);
31251f49692SMarouene Boubakri }
31351f49692SMarouene Boubakri
mutex_read_trylock(struct mutex * m)31451f49692SMarouene Boubakri bool mutex_read_trylock(struct mutex *m)
31551f49692SMarouene Boubakri {
31651f49692SMarouene Boubakri return __mutex_read_trylock(m, NULL, -1);
31751f49692SMarouene Boubakri }
31851f49692SMarouene Boubakri #endif
31951f49692SMarouene Boubakri
mutex_destroy(struct mutex * m)32051f49692SMarouene Boubakri void mutex_destroy(struct mutex *m)
32151f49692SMarouene Boubakri {
32251f49692SMarouene Boubakri /*
32351f49692SMarouene Boubakri * Caller guarantees that no one will try to take the mutex so
32451f49692SMarouene Boubakri * there's no need to take the spinlock before accessing it.
32551f49692SMarouene Boubakri */
32651f49692SMarouene Boubakri if (m->state)
32751f49692SMarouene Boubakri panic();
32851f49692SMarouene Boubakri if (!wq_is_empty(&m->wq))
32951f49692SMarouene Boubakri panic("waitqueue not empty");
33051f49692SMarouene Boubakri mutex_destroy_check(m);
33151f49692SMarouene Boubakri }
33251f49692SMarouene Boubakri
mutex_destroy_recursive(struct recursive_mutex * m)33351f49692SMarouene Boubakri void mutex_destroy_recursive(struct recursive_mutex *m)
33451f49692SMarouene Boubakri {
33551f49692SMarouene Boubakri mutex_destroy(&m->m);
33651f49692SMarouene Boubakri }
33751f49692SMarouene Boubakri
mutex_get_recursive_lock_depth(struct recursive_mutex * m)33851f49692SMarouene Boubakri unsigned int mutex_get_recursive_lock_depth(struct recursive_mutex *m)
33951f49692SMarouene Boubakri {
34051f49692SMarouene Boubakri assert_have_no_spinlock();
34151f49692SMarouene Boubakri assert(m->owner == thread_get_id());
34251f49692SMarouene Boubakri
34351f49692SMarouene Boubakri return refcount_val(&m->lock_depth);
34451f49692SMarouene Boubakri }
34551f49692SMarouene Boubakri
mutex_pm_aware_init(struct mutex_pm_aware * m)3463a20c661SEtienne Carriere void mutex_pm_aware_init(struct mutex_pm_aware *m)
3473a20c661SEtienne Carriere {
3483a20c661SEtienne Carriere *m = (struct mutex_pm_aware)MUTEX_PM_AWARE_INITIALIZER;
3493a20c661SEtienne Carriere }
3503a20c661SEtienne Carriere
mutex_pm_aware_destroy(struct mutex_pm_aware * m)3513a20c661SEtienne Carriere void mutex_pm_aware_destroy(struct mutex_pm_aware *m)
3523a20c661SEtienne Carriere {
3533a20c661SEtienne Carriere mutex_destroy(&m->mutex);
3543a20c661SEtienne Carriere }
3553a20c661SEtienne Carriere
mutex_pm_aware_lock(struct mutex_pm_aware * m)3563a20c661SEtienne Carriere void mutex_pm_aware_lock(struct mutex_pm_aware *m)
3573a20c661SEtienne Carriere {
3583a20c661SEtienne Carriere if (thread_get_id_may_fail() == THREAD_ID_INVALID) {
3593a20c661SEtienne Carriere if (!cpu_spin_trylock(&m->lock) || m->mutex.state)
3603a20c661SEtienne Carriere panic();
3613a20c661SEtienne Carriere } else {
3623a20c661SEtienne Carriere mutex_lock(&m->mutex);
3633a20c661SEtienne Carriere if (!thread_spin_trylock(&m->lock))
3643a20c661SEtienne Carriere panic();
3653a20c661SEtienne Carriere }
3663a20c661SEtienne Carriere }
3673a20c661SEtienne Carriere
mutex_pm_aware_unlock(struct mutex_pm_aware * m)3683a20c661SEtienne Carriere void mutex_pm_aware_unlock(struct mutex_pm_aware *m)
3693a20c661SEtienne Carriere {
3703a20c661SEtienne Carriere if (thread_get_id_may_fail() == THREAD_ID_INVALID) {
3713a20c661SEtienne Carriere assert(!m->mutex.state);
3723a20c661SEtienne Carriere cpu_spin_unlock(&m->lock);
3733a20c661SEtienne Carriere } else {
3743a20c661SEtienne Carriere thread_spin_unlock(&m->lock);
3753a20c661SEtienne Carriere mutex_unlock(&m->mutex);
3763a20c661SEtienne Carriere }
3773a20c661SEtienne Carriere }
3783a20c661SEtienne Carriere
condvar_init(struct condvar * cv)37951f49692SMarouene Boubakri void condvar_init(struct condvar *cv)
38051f49692SMarouene Boubakri {
38151f49692SMarouene Boubakri *cv = (struct condvar)CONDVAR_INITIALIZER;
38251f49692SMarouene Boubakri }
38351f49692SMarouene Boubakri
condvar_destroy(struct condvar * cv)38451f49692SMarouene Boubakri void condvar_destroy(struct condvar *cv)
38551f49692SMarouene Boubakri {
38651f49692SMarouene Boubakri if (cv->m && wq_have_condvar(&cv->m->wq, cv))
38751f49692SMarouene Boubakri panic();
38851f49692SMarouene Boubakri
38951f49692SMarouene Boubakri condvar_init(cv);
39051f49692SMarouene Boubakri }
39151f49692SMarouene Boubakri
cv_signal(struct condvar * cv,bool only_one,const char * fname,int lineno)39251f49692SMarouene Boubakri static void cv_signal(struct condvar *cv, bool only_one, const char *fname,
39351f49692SMarouene Boubakri int lineno)
39451f49692SMarouene Boubakri {
39551f49692SMarouene Boubakri uint32_t old_itr_status;
39651f49692SMarouene Boubakri struct mutex *m;
39751f49692SMarouene Boubakri
39851f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&cv->spin_lock);
39951f49692SMarouene Boubakri m = cv->m;
40051f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&cv->spin_lock, old_itr_status);
40151f49692SMarouene Boubakri
40251f49692SMarouene Boubakri if (m)
40351f49692SMarouene Boubakri wq_promote_condvar(&m->wq, cv, only_one, m, fname, lineno);
40451f49692SMarouene Boubakri
40551f49692SMarouene Boubakri }
40651f49692SMarouene Boubakri
40751f49692SMarouene Boubakri #ifdef CFG_MUTEX_DEBUG
condvar_signal_debug(struct condvar * cv,const char * fname,int lineno)40851f49692SMarouene Boubakri void condvar_signal_debug(struct condvar *cv, const char *fname, int lineno)
40951f49692SMarouene Boubakri {
41051f49692SMarouene Boubakri cv_signal(cv, true /* only one */, fname, lineno);
41151f49692SMarouene Boubakri }
41251f49692SMarouene Boubakri
condvar_broadcast_debug(struct condvar * cv,const char * fname,int lineno)41351f49692SMarouene Boubakri void condvar_broadcast_debug(struct condvar *cv, const char *fname, int lineno)
41451f49692SMarouene Boubakri {
41551f49692SMarouene Boubakri cv_signal(cv, false /* all */, fname, lineno);
41651f49692SMarouene Boubakri }
41751f49692SMarouene Boubakri
41851f49692SMarouene Boubakri #else
condvar_signal(struct condvar * cv)41951f49692SMarouene Boubakri void condvar_signal(struct condvar *cv)
42051f49692SMarouene Boubakri {
42151f49692SMarouene Boubakri cv_signal(cv, true /* only one */, NULL, -1);
42251f49692SMarouene Boubakri }
42351f49692SMarouene Boubakri
condvar_broadcast(struct condvar * cv)42451f49692SMarouene Boubakri void condvar_broadcast(struct condvar *cv)
42551f49692SMarouene Boubakri {
42651f49692SMarouene Boubakri cv_signal(cv, false /* all */, NULL, -1);
42751f49692SMarouene Boubakri }
42851f49692SMarouene Boubakri #endif /*CFG_MUTEX_DEBUG*/
42951f49692SMarouene Boubakri
__condvar_wait_timeout(struct condvar * cv,struct mutex * m,uint32_t timeout_ms,const char * fname,int lineno)430*ea413ca5SGavin Liu static TEE_Result __condvar_wait_timeout(struct condvar *cv, struct mutex *m,
431*ea413ca5SGavin Liu uint32_t timeout_ms, const char *fname,
432*ea413ca5SGavin Liu int lineno)
43351f49692SMarouene Boubakri {
434*ea413ca5SGavin Liu TEE_Result res = TEE_SUCCESS;
435*ea413ca5SGavin Liu uint32_t old_itr_status = 0;
436*ea413ca5SGavin Liu struct wait_queue_elem wqe = { };
437*ea413ca5SGavin Liu short old_state = 0;
438*ea413ca5SGavin Liu short new_state = 0;
43951f49692SMarouene Boubakri
44051f49692SMarouene Boubakri mutex_unlock_check(m);
44151f49692SMarouene Boubakri
44251f49692SMarouene Boubakri /* Link this condvar to this mutex until reinitialized */
44351f49692SMarouene Boubakri old_itr_status = cpu_spin_lock_xsave(&cv->spin_lock);
44451f49692SMarouene Boubakri if (cv->m && cv->m != m)
44551f49692SMarouene Boubakri panic("invalid mutex");
44651f49692SMarouene Boubakri
44751f49692SMarouene Boubakri cv->m = m;
44851f49692SMarouene Boubakri cpu_spin_unlock(&cv->spin_lock);
44951f49692SMarouene Boubakri
45051f49692SMarouene Boubakri cpu_spin_lock(&m->spin_lock);
45151f49692SMarouene Boubakri
45251f49692SMarouene Boubakri if (!m->state)
45351f49692SMarouene Boubakri panic();
45451f49692SMarouene Boubakri old_state = m->state;
45551f49692SMarouene Boubakri /* Add to mutex wait queue as a condvar waiter */
45651f49692SMarouene Boubakri wq_wait_init_condvar(&m->wq, &wqe, cv, m->state > 0);
45751f49692SMarouene Boubakri
45851f49692SMarouene Boubakri if (m->state > 1) {
45951f49692SMarouene Boubakri /* Multiple read locks, remove one */
46051f49692SMarouene Boubakri m->state--;
46151f49692SMarouene Boubakri } else {
46251f49692SMarouene Boubakri /* Only one lock (read or write), unlock the mutex */
46351f49692SMarouene Boubakri m->state = 0;
46451f49692SMarouene Boubakri }
46551f49692SMarouene Boubakri new_state = m->state;
46651f49692SMarouene Boubakri
46751f49692SMarouene Boubakri cpu_spin_unlock_xrestore(&m->spin_lock, old_itr_status);
46851f49692SMarouene Boubakri
46951f49692SMarouene Boubakri /* Wake eventual waiters if the mutex was unlocked */
47051f49692SMarouene Boubakri if (!new_state)
47151f49692SMarouene Boubakri wq_wake_next(&m->wq, m, fname, lineno);
47251f49692SMarouene Boubakri
473*ea413ca5SGavin Liu res = wq_wait_final(&m->wq, &wqe, timeout_ms, m, fname, lineno);
47451f49692SMarouene Boubakri
47551f49692SMarouene Boubakri if (old_state > 0)
47651f49692SMarouene Boubakri mutex_read_lock(m);
47751f49692SMarouene Boubakri else
47851f49692SMarouene Boubakri mutex_lock(m);
479*ea413ca5SGavin Liu
480*ea413ca5SGavin Liu return res;
48151f49692SMarouene Boubakri }
48251f49692SMarouene Boubakri
48351f49692SMarouene Boubakri #ifdef CFG_MUTEX_DEBUG
condvar_wait_debug(struct condvar * cv,struct mutex * m,const char * fname,int lineno)48451f49692SMarouene Boubakri void condvar_wait_debug(struct condvar *cv, struct mutex *m,
48551f49692SMarouene Boubakri const char *fname, int lineno)
48651f49692SMarouene Boubakri {
487*ea413ca5SGavin Liu __condvar_wait_timeout(cv, m, 0, fname, lineno);
488*ea413ca5SGavin Liu }
489*ea413ca5SGavin Liu
condvar_wait_timeout_debug(struct condvar * cv,struct mutex * m,uint32_t timeout_ms,const char * fname,int lineno)490*ea413ca5SGavin Liu TEE_Result condvar_wait_timeout_debug(struct condvar *cv, struct mutex *m,
491*ea413ca5SGavin Liu uint32_t timeout_ms, const char *fname,
492*ea413ca5SGavin Liu int lineno)
493*ea413ca5SGavin Liu {
494*ea413ca5SGavin Liu return __condvar_wait_timeout(cv, m, timeout_ms, fname, lineno);
49551f49692SMarouene Boubakri }
49651f49692SMarouene Boubakri #else
condvar_wait(struct condvar * cv,struct mutex * m)49751f49692SMarouene Boubakri void condvar_wait(struct condvar *cv, struct mutex *m)
49851f49692SMarouene Boubakri {
499*ea413ca5SGavin Liu __condvar_wait_timeout(cv, m, 0, NULL, -1);
500*ea413ca5SGavin Liu }
501*ea413ca5SGavin Liu
condvar_wait_timeout(struct condvar * cv,struct mutex * m,uint32_t timeout_ms)502*ea413ca5SGavin Liu TEE_Result condvar_wait_timeout(struct condvar *cv, struct mutex *m,
503*ea413ca5SGavin Liu uint32_t timeout_ms)
504*ea413ca5SGavin Liu {
505*ea413ca5SGavin Liu return __condvar_wait_timeout(cv, m, timeout_ms, NULL, -1);
50651f49692SMarouene Boubakri }
50751f49692SMarouene Boubakri #endif
508