1 /*
2  * Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  *    contributors may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 #include "nrfx_atomic.h"
32 
33 #ifndef NRFX_ATOMIC_USE_BUILT_IN
34     #define NRFX_ATOMIC_USE_BUILT_IN 0
35 #endif // NRFX_ATOMIC_USE_BUILT_IN
36 
37 #if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U))
38 #define NRFX_ATOMIC_STREX_LDREX_PRESENT
39 #endif
40 
41 #if (NRFX_ATOMIC_USE_BUILT_IN == 0) && defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
42 #include "nrfx_atomic_internal.h"
43 #endif
44 
nrfx_atomic_u32_fetch_store(nrfx_atomic_u32_t * p_data,uint32_t value)45 uint32_t nrfx_atomic_u32_fetch_store(nrfx_atomic_u32_t * p_data, uint32_t value)
46 {
47 #if NRFX_ATOMIC_USE_BUILT_IN
48     return __atomic_exchange_n(p_data, value, __ATOMIC_SEQ_CST);
49 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
50     uint32_t old_val;
51     uint32_t new_val;
52     NRFX_ATOMIC_OP(mov, old_val, new_val, p_data, value);
53     (void) new_val;
54     return old_val;
55 #else
56     NRFX_CRITICAL_SECTION_ENTER();
57     uint32_t old_val = *p_data;
58     *p_data = value;
59     NRFX_CRITICAL_SECTION_EXIT();
60     return old_val;
61 #endif // NRFX_ATOMIC_USE_BUILT_IN
62 }
63 
nrfx_atomic_u32_store(nrfx_atomic_u32_t * p_data,uint32_t value)64 uint32_t nrfx_atomic_u32_store(nrfx_atomic_u32_t * p_data, uint32_t value)
65 {
66 #if NRFX_ATOMIC_USE_BUILT_IN
67     __atomic_store_n(p_data, value, __ATOMIC_SEQ_CST);
68     return value;
69 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
70     uint32_t old_val;
71     uint32_t new_val;
72     NRFX_ATOMIC_OP(mov, old_val, new_val, p_data, value);
73     (void) old_val;
74     return new_val;
75 #else
76     NRFX_CRITICAL_SECTION_ENTER();
77     *p_data = value;
78     NRFX_CRITICAL_SECTION_EXIT();
79     return value;
80 #endif //NRFX_ATOMIC_USE_BUILT_IN
81 }
82 
nrfx_atomic_u32_fetch_or(nrfx_atomic_u32_t * p_data,uint32_t value)83 uint32_t nrfx_atomic_u32_fetch_or(nrfx_atomic_u32_t * p_data, uint32_t value)
84 {
85 #if NRFX_ATOMIC_USE_BUILT_IN
86     return __atomic_fetch_or(p_data, value, __ATOMIC_SEQ_CST);
87 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
88     uint32_t old_val;
89     uint32_t new_val;
90     NRFX_ATOMIC_OP(orr, old_val, new_val, p_data, value);
91     (void) new_val;
92     return old_val;
93 #else
94     NRFX_CRITICAL_SECTION_ENTER();
95     uint32_t old_val = *p_data;
96     *p_data |= value;
97     NRFX_CRITICAL_SECTION_EXIT();
98     return old_val;
99 #endif //NRFX_ATOMIC_USE_BUILT_IN
100 }
101 
nrfx_atomic_u32_or(nrfx_atomic_u32_t * p_data,uint32_t value)102 uint32_t nrfx_atomic_u32_or(nrfx_atomic_u32_t * p_data, uint32_t value)
103 {
104 #if NRFX_ATOMIC_USE_BUILT_IN
105     return __atomic_or_fetch(p_data, value, __ATOMIC_SEQ_CST);
106 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
107     uint32_t old_val;
108     uint32_t new_val;
109     NRFX_ATOMIC_OP(orr, old_val, new_val, p_data, value);
110     (void) old_val;
111     return new_val;
112 #else
113     NRFX_CRITICAL_SECTION_ENTER();
114     *p_data |= value;
115     uint32_t new_value = *p_data;
116     NRFX_CRITICAL_SECTION_EXIT();
117     return new_value;
118 #endif //NRFX_ATOMIC_USE_BUILT_IN
119 }
120 
nrfx_atomic_u32_fetch_and(nrfx_atomic_u32_t * p_data,uint32_t value)121 uint32_t nrfx_atomic_u32_fetch_and(nrfx_atomic_u32_t * p_data, uint32_t value)
122 {
123 #if NRFX_ATOMIC_USE_BUILT_IN
124     return __atomic_fetch_and(p_data, value, __ATOMIC_SEQ_CST);
125 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
126     uint32_t old_val;
127     uint32_t new_val;
128     NRFX_ATOMIC_OP(and, old_val, new_val, p_data, value);
129     (void) new_val;
130     return old_val;
131 #else
132     NRFX_CRITICAL_SECTION_ENTER();
133     uint32_t old_val = *p_data;
134     *p_data &= value;
135     NRFX_CRITICAL_SECTION_EXIT();
136     return old_val;
137 #endif //NRFX_ATOMIC_USE_BUILT_IN
138 }
139 
nrfx_atomic_u32_and(nrfx_atomic_u32_t * p_data,uint32_t value)140 uint32_t nrfx_atomic_u32_and(nrfx_atomic_u32_t * p_data, uint32_t value)
141 {
142 #if NRFX_ATOMIC_USE_BUILT_IN
143     return __atomic_and_fetch(p_data, value, __ATOMIC_SEQ_CST);
144 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
145     uint32_t old_val;
146     uint32_t new_val;
147     NRFX_ATOMIC_OP(and, old_val, new_val, p_data, value);
148     (void) old_val;
149     return new_val;
150 #else
151     NRFX_CRITICAL_SECTION_ENTER();
152     *p_data &= value;
153     uint32_t new_value = *p_data;
154     NRFX_CRITICAL_SECTION_EXIT();
155     return new_value;
156 #endif //NRFX_ATOMIC_USE_BUILT_IN
157 }
158 
nrfx_atomic_u32_fetch_xor(nrfx_atomic_u32_t * p_data,uint32_t value)159 uint32_t nrfx_atomic_u32_fetch_xor(nrfx_atomic_u32_t * p_data, uint32_t value)
160 {
161 #if NRFX_ATOMIC_USE_BUILT_IN
162     return __atomic_fetch_xor(p_data, value, __ATOMIC_SEQ_CST);
163 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
164     uint32_t old_val;
165     uint32_t new_val;
166     NRFX_ATOMIC_OP(eor, old_val, new_val, p_data, value);
167     (void) new_val;
168     return old_val;
169 #else
170     NRFX_CRITICAL_SECTION_ENTER();
171     uint32_t old_val = *p_data;
172     *p_data ^= value;
173     NRFX_CRITICAL_SECTION_EXIT();
174     return old_val;
175 #endif //NRFX_ATOMIC_USE_BUILT_IN
176 }
177 
nrfx_atomic_u32_xor(nrfx_atomic_u32_t * p_data,uint32_t value)178 uint32_t nrfx_atomic_u32_xor(nrfx_atomic_u32_t * p_data, uint32_t value)
179 {
180 #if NRFX_ATOMIC_USE_BUILT_IN
181     return __atomic_xor_fetch(p_data, value, __ATOMIC_SEQ_CST);
182 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
183     uint32_t old_val;
184     uint32_t new_val;
185     NRFX_ATOMIC_OP(eor, old_val, new_val, p_data, value);
186     (void) old_val;
187     return new_val;
188 #else
189     NRFX_CRITICAL_SECTION_ENTER();
190     *p_data ^= value;
191     uint32_t new_value = *p_data;
192     NRFX_CRITICAL_SECTION_EXIT();
193     return new_value;
194 #endif //NRFX_ATOMIC_USE_BUILT_IN
195 }
196 
nrfx_atomic_u32_fetch_add(nrfx_atomic_u32_t * p_data,uint32_t value)197 uint32_t nrfx_atomic_u32_fetch_add(nrfx_atomic_u32_t * p_data, uint32_t value)
198 {
199 #if NRFX_ATOMIC_USE_BUILT_IN
200     return __atomic_fetch_add(p_data, value, __ATOMIC_SEQ_CST);
201 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
202     uint32_t old_val;
203     uint32_t new_val;
204     NRFX_ATOMIC_OP(add, old_val, new_val, p_data, value);
205     (void) new_val;
206     return old_val;
207 #else
208     NRFX_CRITICAL_SECTION_ENTER();
209     uint32_t old_val = *p_data;
210     *p_data += value;
211     NRFX_CRITICAL_SECTION_EXIT();
212     return old_val;
213 #endif //NRFX_ATOMIC_USE_BUILT_IN
214 }
215 
nrfx_atomic_u32_add(nrfx_atomic_u32_t * p_data,uint32_t value)216 uint32_t nrfx_atomic_u32_add(nrfx_atomic_u32_t * p_data, uint32_t value)
217 {
218 #if NRFX_ATOMIC_USE_BUILT_IN
219     return __atomic_add_fetch(p_data, value, __ATOMIC_SEQ_CST);
220 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
221     uint32_t old_val;
222     uint32_t new_val;
223     NRFX_ATOMIC_OP(add, old_val, new_val, p_data, value);
224     (void) old_val;
225     return new_val;
226 #else
227     NRFX_CRITICAL_SECTION_ENTER();
228     *p_data += value;
229     uint32_t new_value = *p_data;
230     NRFX_CRITICAL_SECTION_EXIT();
231     return new_value;
232 #endif //NRFX_ATOMIC_USE_BUILT_IN
233 }
234 
nrfx_atomic_u32_fetch_sub(nrfx_atomic_u32_t * p_data,uint32_t value)235 uint32_t nrfx_atomic_u32_fetch_sub(nrfx_atomic_u32_t * p_data, uint32_t value)
236 {
237 #if NRFX_ATOMIC_USE_BUILT_IN
238     return __atomic_fetch_sub(p_data, value, __ATOMIC_SEQ_CST);
239 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
240     uint32_t old_val;
241     uint32_t new_val;
242     NRFX_ATOMIC_OP(sub, old_val, new_val, p_data, value);
243     (void) new_val;
244     return old_val;
245 #else
246     NRFX_CRITICAL_SECTION_ENTER();
247     uint32_t old_val = *p_data;
248     *p_data -= value;
249     NRFX_CRITICAL_SECTION_EXIT();
250     return old_val;
251 #endif //NRFX_ATOMIC_USE_BUILT_IN
252 }
253 
nrfx_atomic_u32_sub(nrfx_atomic_u32_t * p_data,uint32_t value)254 uint32_t nrfx_atomic_u32_sub(nrfx_atomic_u32_t * p_data, uint32_t value)
255 {
256 #if NRFX_ATOMIC_USE_BUILT_IN
257     return __atomic_sub_fetch(p_data, value, __ATOMIC_SEQ_CST);
258 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
259     uint32_t old_val;
260     uint32_t new_val;
261     NRFX_ATOMIC_OP(sub, old_val, new_val, p_data, value);
262     (void) old_val;
263     return new_val;
264 #else
265     NRFX_CRITICAL_SECTION_ENTER();
266     *p_data -= value;
267     uint32_t new_value = *p_data;
268     NRFX_CRITICAL_SECTION_EXIT();
269     return new_value;
270 #endif //NRFX_ATOMIC_USE_BUILT_IN
271 }
272 
nrfx_atomic_u32_cmp_exch(nrfx_atomic_u32_t * p_data,uint32_t * p_expected,uint32_t desired)273 bool nrfx_atomic_u32_cmp_exch(nrfx_atomic_u32_t * p_data,
274                               uint32_t *          p_expected,
275                               uint32_t            desired)
276 {
277 #if NRFX_ATOMIC_USE_BUILT_IN
278     return __atomic_compare_exchange(p_data,
279                                      p_expected,
280                                      &desired,
281                                      1,
282                                      __ATOMIC_SEQ_CST,
283                                      __ATOMIC_SEQ_CST);
284 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
285     return nrfx_atomic_internal_cmp_exch(p_data, p_expected, desired);
286 #else
287     bool result;
288     NRFX_CRITICAL_SECTION_ENTER();
289     if (*p_data == *p_expected)
290     {
291         *p_data = desired;
292         result = true;
293     }
294     else
295     {
296         *p_expected = *p_data;
297         result = false;
298     }
299     NRFX_CRITICAL_SECTION_EXIT();
300     return result;
301 #endif
302 }
303 
nrfx_atomic_u32_fetch_sub_hs(nrfx_atomic_u32_t * p_data,uint32_t value)304 uint32_t nrfx_atomic_u32_fetch_sub_hs(nrfx_atomic_u32_t * p_data, uint32_t value)
305 {
306 #if NRFX_ATOMIC_USE_BUILT_IN
307     uint32_t expected = *p_data;
308     uint32_t new_val;
309     do {
310         if (expected >= value)
311         {
312             new_val = expected - value;
313         }
314         else
315         {
316             new_val = expected;
317         }
318     } while (!__atomic_compare_exchange(p_data, &expected, &new_val,
319                                         1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
320     return expected;
321 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
322     uint32_t old_val;
323     uint32_t new_val;
324     NRFX_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value);
325     (void) new_val;
326     return old_val;
327 #else
328     NRFX_CRITICAL_SECTION_ENTER();
329     uint32_t old_val = *p_data;
330     *p_data -= value;
331     NRFX_CRITICAL_SECTION_EXIT();
332     return old_val;
333 #endif //NRFX_ATOMIC_USE_BUILT_IN
334 }
335 
nrfx_atomic_u32_sub_hs(nrfx_atomic_u32_t * p_data,uint32_t value)336 uint32_t nrfx_atomic_u32_sub_hs(nrfx_atomic_u32_t * p_data, uint32_t value)
337 {
338 #if NRFX_ATOMIC_USE_BUILT_IN
339     uint32_t expected = *p_data;
340     uint32_t new_val;
341     do {
342         if (expected >= value)
343         {
344             new_val = expected - value;
345         }
346         else
347         {
348             new_val = expected;
349         }
350     } while (!__atomic_compare_exchange(p_data, &expected, &new_val,
351                                         1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
352     return new_val;
353 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
354     uint32_t old_val;
355     uint32_t new_val;
356     NRFX_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value);
357     (void) old_val;
358     return new_val;
359 #else
360     NRFX_CRITICAL_SECTION_ENTER();
361     *p_data -= value;
362     uint32_t new_value = *p_data;
363     NRFX_CRITICAL_SECTION_EXIT();
364     return new_value;
365 #endif //NRFX_ATOMIC_USE_BUILT_IN
366 }
367 
nrfx_atomic_flag_set_fetch(nrfx_atomic_flag_t * p_data)368 uint32_t nrfx_atomic_flag_set_fetch(nrfx_atomic_flag_t * p_data)
369 {
370     return nrfx_atomic_u32_fetch_or(p_data, 1);
371 }
372 
nrfx_atomic_flag_set(nrfx_atomic_flag_t * p_data)373 uint32_t nrfx_atomic_flag_set(nrfx_atomic_flag_t * p_data)
374 {
375     return nrfx_atomic_u32_or(p_data, 1);
376 }
377 
nrfx_atomic_flag_clear_fetch(nrfx_atomic_flag_t * p_data)378 uint32_t nrfx_atomic_flag_clear_fetch(nrfx_atomic_flag_t * p_data)
379 {
380     return nrfx_atomic_u32_fetch_and(p_data, 0);
381 }
382 
nrfx_atomic_flag_clear(nrfx_atomic_flag_t * p_data)383 uint32_t nrfx_atomic_flag_clear(nrfx_atomic_flag_t * p_data)
384 {
385     return nrfx_atomic_u32_and(p_data, 0);
386 }
387