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