1 /*
2 * Copyright (c) 2014 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 #pragma once
24
25 #include <compiler.h>
26 #include <arch/ops.h>
27 #include <stdbool.h>
28
29 __BEGIN_CDECLS;
30
31 #define SPIN_LOCK_INITIAL_VALUE (0)
32
33 typedef unsigned long spin_lock_t;
34
35 typedef unsigned long spin_lock_saved_state_t;
36 typedef unsigned long spin_lock_save_flags_t;
37
arch_spin_lock_init(spin_lock_t * lock)38 static inline void arch_spin_lock_init(spin_lock_t *lock)
39 {
40 *lock = SPIN_LOCK_INITIAL_VALUE;
41 }
42
arch_spin_lock_held(spin_lock_t * lock)43 static inline bool arch_spin_lock_held(spin_lock_t *lock)
44 {
45 return *lock != 0;
46 }
47
48 #if WITH_SMP
49
50 void arch_spin_lock(spin_lock_t *lock);
51 int arch_spin_trylock(spin_lock_t *lock);
52 void arch_spin_unlock(spin_lock_t *lock);
53
54 #else
55
arch_spin_lock(spin_lock_t * lock)56 static inline void arch_spin_lock(spin_lock_t *lock)
57 {
58 *lock = 1;
59 }
60
arch_spin_trylock(spin_lock_t * lock)61 static inline int arch_spin_trylock(spin_lock_t *lock)
62 {
63 return 0;
64 }
65
arch_spin_unlock(spin_lock_t * lock)66 static inline void arch_spin_unlock(spin_lock_t *lock)
67 {
68 *lock = 0;
69 }
70
71 #endif
72
73 /* ARM specific flags */
74 #define SPIN_LOCK_FLAG_IRQ 0x40000000
75 #define SPIN_LOCK_FLAG_FIQ 0x80000000 /* Do not use unless IRQs are already disabled */
76 #define SPIN_LOCK_FLAG_IRQ_FIQ (SPIN_LOCK_FLAG_IRQ | SPIN_LOCK_FLAG_FIQ)
77
78 /* default arm flag is to just disable plain irqs */
79 #define ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS SPIN_LOCK_FLAG_IRQ
80
81 enum {
82 /* private */
83 SPIN_LOCK_STATE_RESTORE_IRQ = 1,
84 SPIN_LOCK_STATE_RESTORE_FIQ = 2,
85 };
86
87 static inline void
arch_interrupt_save(spin_lock_saved_state_t * statep,spin_lock_save_flags_t flags)88 arch_interrupt_save(spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags)
89 {
90 spin_lock_saved_state_t state = 0;
91 if ((flags & SPIN_LOCK_FLAG_IRQ) && !arch_ints_disabled()) {
92 state |= SPIN_LOCK_STATE_RESTORE_IRQ;
93 arch_disable_ints();
94 }
95 if ((flags & SPIN_LOCK_FLAG_FIQ) && !arch_fiqs_disabled()) {
96 state |= SPIN_LOCK_STATE_RESTORE_FIQ;
97 arch_disable_fiqs();
98 }
99 *statep = state;
100 }
101
102 static inline void
arch_interrupt_restore(spin_lock_saved_state_t old_state,spin_lock_save_flags_t flags)103 arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags)
104 {
105 if ((flags & SPIN_LOCK_FLAG_FIQ) && (old_state & SPIN_LOCK_STATE_RESTORE_FIQ))
106 arch_enable_fiqs();
107 if ((flags & SPIN_LOCK_FLAG_IRQ) && (old_state & SPIN_LOCK_STATE_RESTORE_IRQ))
108 arch_enable_ints();
109 }
110
111 __END_CDECLS;
112