1 /*
2 * Copyright (c) 2017, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35 #ifndef NRF_802154_SL_ATOMICS_H__
36 #define NRF_802154_SL_ATOMICS_H__
37
38 #include <stdbool.h>
39 #include <stdint.h>
40 #include <nrfx.h>
41
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45
46 /**@brief Type representing a mutex */
47 typedef volatile uint32_t nrf_802154_sl_mutex_t;
48
49 /**@brief Initializes a mutex
50 *
51 * @param p_mutex Pointer to a mutex to initialize, must not be NULL.
52 */
53 void nrf_802154_sl_mutex_init(nrf_802154_sl_mutex_t * p_mutex);
54
55 /** @brief Tries to take a non-blocking mutex.
56 *
57 * @param p_mutex Pointer to a mutex to acquire, must not be NULL.
58 *
59 * @retval true Mutex was acquired.
60 * @retval false Mutex could not be acquired, because it was already acquired.
61 * This will cause the nearest call to @ref nrf_802154_sl_mutex_release to return
62 * `true`
63 */
64 bool nrf_802154_sl_mutex_try_acquire(nrf_802154_sl_mutex_t * p_mutex);
65
66 /**@brief Releases a non-blocking mutex.
67 *
68 * @note Attempt to release a non-acquired mutex is an undefined behavior.
69 *
70 * @param p_mutex Pointer to a mutex to release, must not be NULL.
71 *
72 * @retval false No other context tried to acquire mutex while it was taken.
73 * @retval true Some other context tried to acquire the mutex while it was already taken.
74 */
75 bool nrf_802154_sl_mutex_release(nrf_802154_sl_mutex_t * p_mutex);
76
77 /**@brief Type representing an atomic uint8_t */
78 typedef volatile uint8_t nrf_802154_sl_atomic_uint8_t;
79
80 /**@brief Atomic increase of uint8_t value.
81 *
82 * Performs following code in an atomic way:
83 * @code
84 * *(p_value)++;
85 * @endcode
86 *
87 * @param p_value Pointer to a value to be incremented.
88 */
89 void nrf_802154_sl_atomic_uint8_inc(nrf_802154_sl_atomic_uint8_t * p_value);
90
91 /**@brief Atomic strong compare-and-swap operation (word variant).
92 *
93 * Performs compare-and-swap operation with sequentially consistent memory ordering.
94 *
95 * @param[in] p_obj Atomic variable object.
96 * @param[in] p_expected Pointer to expected value.
97 * In case of CAS failure the argument will be updated with current obj value.
98 * @param[in] desired Desired object value.
99 *
100 * @retval true The object was assigned new value.
101 * @retval false The object was not modified.
102 */
nrf_802154_sl_atomic_cas_u32(uint32_t * p_obj,uint32_t * p_expected,uint32_t desired)103 static inline bool nrf_802154_sl_atomic_cas_u32(uint32_t * p_obj,
104 uint32_t * p_expected,
105 uint32_t desired)
106 {
107 __DMB();
108
109 do
110 {
111 uint32_t old_val = __LDREXW((volatile uint32_t *)p_obj);
112
113 if ( old_val != *p_expected)
114 {
115 *p_expected = old_val;
116 __CLREX();
117 return false;
118 }
119 }
120 while (__STREXW(desired, (volatile uint32_t *)p_obj));
121
122 __DMB();
123
124 return true;
125 }
126
127 /**@brief Atomic strong compare-and-swap operation (half-word variant).
128 *
129 * Performs compare-and-swap operation with sequentially consistent memory ordering.
130 *
131 * @param[in] p_obj Atomic variable object.
132 * @param[in] p_expected Pointer to expected value.
133 * In case of CAS failure the argument will be updated with current obj value.
134 * @param[in] desired Desired object value.
135 *
136 * @retval true The object was assigned new value.
137 * @retval false The object was not modified.
138 */
nrf_802154_sl_atomic_cas_u16(uint16_t * p_obj,uint16_t * p_expected,uint16_t desired)139 static inline bool nrf_802154_sl_atomic_cas_u16(uint16_t * p_obj,
140 uint16_t * p_expected,
141 uint16_t desired)
142 {
143 __DMB();
144
145 do
146 {
147 uint16_t old_val = __LDREXH((volatile uint16_t *)p_obj);
148
149 if ( old_val != *p_expected)
150 {
151 *p_expected = old_val;
152 __CLREX();
153 return false;
154 }
155 }
156 while (__STREXH(desired, (volatile uint16_t *)p_obj));
157
158 __DMB();
159
160 return true;
161 }
162
163 /**@brief Atomic strong compare-and-swap operation (byte variant).
164 *
165 * Performs compare-and-swap operation with sequentially consistent memory ordering.
166 *
167 * @param[in] p_obj Atomic variable object.
168 * @param[in] p_expected Pointer to expected value.
169 * In case of CAS failure the argument will be updated with current obj value.
170 * @param[in] desired Desired object value.
171 *
172 * @retval true The object was assigned new value.
173 * @retval false The object was not modified.
174 */
nrf_802154_sl_atomic_cas_u8(uint8_t * p_obj,uint8_t * p_expected,uint8_t desired)175 static inline bool nrf_802154_sl_atomic_cas_u8(uint8_t * p_obj,
176 uint8_t * p_expected,
177 uint8_t desired)
178 {
179 __DMB();
180
181 do
182 {
183 uint8_t old_val = __LDREXB((volatile uint8_t *)p_obj);
184
185 if ( old_val != *p_expected)
186 {
187 *p_expected = old_val;
188 __CLREX();
189 return false;
190 }
191 }
192 while (__STREXB(desired, (volatile uint8_t *)p_obj));
193
194 __DMB();
195
196 return true;
197 }
198
199 /**@brief Atomic store operation (word variant).
200 *
201 * Performs store operation with sequentially consistent memory ordering.
202 *
203 * @param[in] p_obj Atomic variable object.
204 * @param[in] value New object value.
205 */
nrf_802154_sl_atomic_store_u32(uint32_t * p_obj,uint32_t value)206 static inline void nrf_802154_sl_atomic_store_u32(uint32_t * p_obj, uint32_t value)
207 {
208 __DMB();
209 *p_obj = value;
210 __DMB();
211 }
212
213 /**@brief Atomic store operation (half-word variant).
214 *
215 * Performs store operation with sequentially consistent memory ordering.
216 *
217 * @param[in] p_obj Atomic variable object.
218 * @param[in] value New object value.
219 */
nrf_802154_sl_atomic_store_u16(uint16_t * p_obj,uint16_t value)220 static inline void nrf_802154_sl_atomic_store_u16(uint16_t * p_obj, uint16_t value)
221 {
222 __DMB();
223 *p_obj = value;
224 __DMB();
225 }
226
227 /**@brief Atomic store operation (byte variant).
228 *
229 * Performs store operation with sequentially consistent memory ordering.
230 *
231 * @param[in] p_obj Atomic variable object.
232 * @param[in] value New object value.
233 */
nrf_802154_sl_atomic_store_u8(uint8_t * p_obj,uint8_t value)234 static inline void nrf_802154_sl_atomic_store_u8(uint8_t * p_obj, uint8_t value)
235 {
236 __DMB();
237 *p_obj = value;
238 __DMB();
239 }
240
241 /**@brief Atomic load operation (word variant).
242 *
243 * Performs load operation with sequentially consistent memory ordering.
244 *
245 * @param[in] p_obj Atomic variable object.
246 */
nrf_802154_sl_atomic_load_u32(uint32_t * p_obj)247 static inline uint32_t nrf_802154_sl_atomic_load_u32(uint32_t * p_obj)
248 {
249 uint32_t value;
250
251 __DMB();
252 value = *p_obj;
253 __DMB();
254
255 return value;
256 }
257
258 /**@brief Atomic load operation (half-word variant).
259 *
260 * Performs load operation with sequentially consistent memory ordering.
261 *
262 * @param[in] p_obj Atomic variable object.
263 */
nrf_802154_sl_atomic_load_u16(uint16_t * p_obj)264 static inline uint16_t nrf_802154_sl_atomic_load_u16(uint16_t * p_obj)
265 {
266 uint16_t value;
267
268 __DMB();
269 value = *p_obj;
270 __DMB();
271
272 return value;
273 }
274
275 /**@brief Atomic load operation (byte variant).
276 *
277 * Performs load operation with sequentially consistent memory ordering.
278 *
279 * @param[in] p_obj Atomic variable object.
280 */
nrf_802154_sl_atomic_load_u8(uint8_t * p_obj)281 static inline uint8_t nrf_802154_sl_atomic_load_u8(uint8_t * p_obj)
282 {
283 uint8_t value;
284
285 __DMB();
286 value = *p_obj;
287 __DMB();
288
289 return value;
290 }
291
292 #ifdef __cplusplus
293 }
294 #endif
295
296 #endif // NRF_802154_SL_ATOMICS_H__
297