Zephyr Project API 4.4.99
A Scalable Open Source RTOS
Loading...
Searching...
No Matches
atomic_xtensa.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021, 2026 Intel Corporation
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_ATOMIC_XTENSA_H_
7#define ZEPHYR_INCLUDE_ARCH_XTENSA_ATOMIC_XTENSA_H_
8
9/* Included from <zephyr/sys/atomic.h> */
10
11#include <xtensa/config/core-isa.h>
12
13/* Recent GCC versions actually do have working atomics support on
14 * Xtensa with S32C1I and so should work with CONFIG_ATOMIC_OPERATIONS_BUILTIN.
15 * Existing versions of Xtensa's XCC do not and GCC also do not support
16 * L32EX/S32EX. So we need to define our own versions of atomic operations
17 * if we have exclusive access.
18 */
19
22{
23 atomic_val_t ret;
24
25 /* Actual Xtensa hardware seems to have only in-order
26 * pipelines, but the architecture does define a barrier load,
27 * so use it. There is a matching s32ri instruction, but
28 * nothing in the Zephyr API requires a barrier store (all the
29 * atomic write ops have exchange semantics.
30 */
31 __asm__ volatile("l32ai %0, %1, 0"
32 : "=r"(ret) : "r"(target) : "memory");
33 return ret;
34}
35
36#if XCHAL_HAVE_EXCLUSIVE || defined(__DOXYGEN__)
37
39static ALWAYS_INLINE
40bool atomic_cas(atomic_t *target, atomic_val_t oldval, atomic_val_t newval)
41{
42 atomic_val_t mem_val;
43 uint32_t result = 0;
44
45 __asm__ volatile(
46 " l32ex %0, %3 ;" /* mem_val = *addr and set exclusive monitor */
47 " bne %0, %4, 1f ;" /* Goto 1 if mem_val != oldval */
48 " s32ex %1, %3 ;" /* Try exclusive store *addr = newval */
49 " getex %2 ;" /* Get exclusive store result */
50 " j 2f ;" /* Store success so jump to 2 to return */
51 " ;"
52 "1: ;" /* 1: Fail as *addr has unexpected value */
53 " clrex ;" /* Clear the monitor and return */
54 " ;"
55 "2: ;"
56 : "=&r"(mem_val), "+&r"(newval), "+&r"(result)
57 : "r"(target), "r"(oldval)
58 : "memory");
59
60 return result == 1;
61}
62
64static ALWAYS_INLINE
65bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval)
66{
67 return atomic_cas((atomic_t *)target, (atomic_val_t)oldval, (atomic_val_t)newval);
68}
69
71static ALWAYS_INLINE
73{
74 atomic_val_t oldval;
75 uint32_t result;
76
77 do {
78 __asm__ volatile(
79 "l32ex %0, %2 ;" /* oldval = *target and set exclusive monitor */
80 "mov %1, %3 ;" /* S32EX writes to %1, so we need scratch register */
81 "s32ex %1, %2 ;" /* Try exclusive store *target = value */
82 "getex %1 ;" /* Get exclusive store result */
83 : "=&r"(oldval), "=&r"(result)
84 : "r"(target), "r"(value)
85 : "memory");
86 } while (result == 0);
87
88 return oldval;
89}
90
92static ALWAYS_INLINE
94{
95 atomic_val_t oldval;
96 uint32_t result;
97
98 do {
99 __asm__ volatile(
100 "l32ex %0, %2 ;" /* oldval = *target and set exclusive monitor */
101 "add %1, %0, %3 ;" /* result = oldval + value */
102 "s32ex %1, %2 ;" /* Try exclusive store *target = result */
103 "getex %1 ;" /* Get exclusive store result */
104 : "=&r"(oldval), "=&r"(result)
105 : "r"(target), "r"(value)
106 : "memory");
107 } while (result == 0);
108
109 return oldval;
110}
111
113static ALWAYS_INLINE
115{
116 atomic_val_t oldval;
117 uint32_t result;
118
119 do {
120 __asm__ volatile(
121 "l32ex %0, %2 ;" /* oldval = *target and set exclusive monitor */
122 "sub %1, %0, %3 ;" /* result = oldval - value */
123 "s32ex %1, %2 ;" /* Try exclusive store *target = result */
124 "getex %1 ;" /* Get exclusive store result */
125 : "=&r"(oldval), "=&r"(result)
126 : "r"(target), "r"(value)
127 : "memory");
128 } while (result == 0);
129
130 return oldval;
131}
132
134static ALWAYS_INLINE
136{
137 atomic_val_t oldval;
138 uint32_t result;
139
140 do {
141 __asm__ volatile(
142 "l32ex %0, %2 ;" /* oldval = *target and set exclusive monitor */
143 "addi %1, %0, 1 ;" /* result = oldval + 1 */
144 "s32ex %1, %2 ;" /* Try exclusive store *target = result */
145 "getex %1 ;" /* Get exclusive store result */
146 : "=&r"(oldval), "=&r"(result)
147 : "r"(target)
148 : "memory");
149 } while (result == 0);
150
151 return oldval;
152}
153
155static ALWAYS_INLINE
157{
158 atomic_val_t oldval;
159 uint32_t result;
160
161 do {
162 __asm__ volatile(
163 "l32ex %0, %2 ;" /* oldval = *target and set exclusive monitor */
164 "addi %1, %0, -1;" /* result = oldval + (-1) */
165 "s32ex %1, %2 ;" /* Try exclusive store *target = result */
166 "getex %1 ;" /* Get exclusive store result */
167 : "=&r"(oldval), "=&r"(result)
168 : "r"(target)
169 : "memory");
170 } while (result == 0);
171
172 return oldval;
173}
174
177{
178 atomic_val_t oldval;
179 uint32_t result;
180
181 do {
182 __asm__ volatile(
183 "l32ex %0, %2 ;" /* oldval = *target and set exclusive monitor */
184 "or %1, %0, %3 ;" /* result = oldval | value */
185 "s32ex %1, %2 ;" /* Try exclusive store *target = result */
186 "getex %1 ;" /* Get exclusive store result */
187 : "=&r"(oldval), "=&r"(result)
188 : "r"(target), "r"(value)
189 : "memory");
190 } while (result == 0);
191
192 return oldval;
193}
194
197{
198 atomic_val_t oldval;
199 uint32_t result;
200
201 do {
202 __asm__ volatile(
203 "l32ex %0, %2 ;" /* oldval = *target and set exclusive monitor */
204 "xor %1, %0, %3 ;" /* result = oldval ^ value */
205 "s32ex %1, %2 ;" /* Try exclusive store *target = result */
206 "getex %1 ;" /* Get exclusive store result */
207 : "=&r"(oldval), "=&r"(result)
208 : "r"(target), "r"(value)
209 : "memory");
210 } while (result == 0);
211
212 return oldval;
213}
214
217 atomic_val_t value)
218{
219 atomic_val_t oldval;
220 uint32_t result;
221
222 do {
223 __asm__ volatile(
224 "l32ex %0, %2 ;" /* oldval = *target and set exclusive monitor */
225 "and %1, %0, %3 ;" /* result = oldval & value */
226 "s32ex %1, %2 ;" /* Try exclusive store *target = result */
227 "getex %1 ;" /* Get exclusive store result */
228 : "=&r"(oldval), "=&r"(result)
229 : "r"(target), "r"(value)
230 : "memory");
231 } while (result == 0);
232
233 return oldval;
234}
235
238 atomic_val_t value)
239{
240 atomic_val_t oldval;
241 uint32_t result;
242
243 do {
244 __asm__ volatile(
245 "l32ex %0, %2 ;" /* oldval = *target and set exclusive monitor */
246 "and %1, %0, %3 ;" /* result = oldval & value */
247 "neg %1, %1 ;" /* result = 0 - result - 1 as bitwise NOT */
248 "addi %1, %1, -1;"
249 "s32ex %1, %2 ;" /* Try exclusive store *target = result */
250 "getex %1 ;" /* Get exclusive store result */
251 : "=&r"(oldval), "=&r"(result)
252 : "r"(target), "r"(value)
253 : "memory");
254 } while (result == 0);
255
256 return oldval;
257}
258
259#elif XCHAL_HAVE_S32C1I
260
278static ALWAYS_INLINE
279atomic_val_t xtensa_cas(atomic_t *addr, atomic_val_t oldval,
280 atomic_val_t newval)
281{
282 __asm__ volatile("wsr %1, SCOMPARE1; s32c1i %0, %2, 0"
283 : "+r"(newval), "+r"(oldval) : "r"(addr) : "memory");
284
285 return newval; /* got swapped with the old memory by s32c1i */
286}
287
289static ALWAYS_INLINE
290bool atomic_cas(atomic_t *target, atomic_val_t oldval, atomic_val_t newval)
291{
292 return oldval == xtensa_cas(target, oldval, newval);
293}
294
296static ALWAYS_INLINE
297bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval)
298{
299 return (atomic_val_t) oldval
300 == xtensa_cas((atomic_t *) target, (atomic_val_t) oldval,
301 (atomic_val_t) newval);
302}
303
304/* Generates an atomic exchange sequence that swaps the value at
305 * address "target", whose old value is read to be "cur", with the
306 * specified expression. Evaluates to the old value which was
307 * atomically replaced.
308 */
309#define Z__GEN_ATOMXCHG(expr) ({ \
310 atomic_val_t res, cur; \
311 do { \
312 cur = *target; \
313 res = xtensa_cas(target, cur, (expr)); \
314 } while (res != cur); \
315 res; })
316
318static ALWAYS_INLINE
320{
321 return Z__GEN_ATOMXCHG(value);
322}
323
325static ALWAYS_INLINE
327{
328 return Z__GEN_ATOMXCHG(cur + value);
329}
330
332static ALWAYS_INLINE
334{
335 return Z__GEN_ATOMXCHG(cur - value);
336}
337
339static ALWAYS_INLINE
341{
342 return Z__GEN_ATOMXCHG(cur + 1);
343}
344
346static ALWAYS_INLINE
348{
349 return Z__GEN_ATOMXCHG(cur - 1);
350}
351
354 atomic_val_t value)
355{
356 return Z__GEN_ATOMXCHG(cur | value);
357}
358
361 atomic_val_t value)
362{
363 return Z__GEN_ATOMXCHG(cur ^ value);
364}
365
368 atomic_val_t value)
369{
370 return Z__GEN_ATOMXCHG(cur & value);
371}
372
375 atomic_val_t value)
376{
377 return Z__GEN_ATOMXCHG(~(cur & value));
378}
379
380#else
381#error "No available hardware support for atomic operations"
382#endif
383
385static ALWAYS_INLINE void *atomic_ptr_get(const atomic_ptr_t *target)
386{
387 return (void *) atomic_get((atomic_t *)target);
388}
389
391static ALWAYS_INLINE void *atomic_ptr_set(atomic_ptr_t *target, void *value)
392{
393 return (void *) atomic_set((atomic_t *) target, (atomic_val_t) value);
394}
395
398{
399 return atomic_set(target, 0);
400}
401
404{
405 return (void *) atomic_set((atomic_t *) target, 0);
406}
407
408#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_ATOMIC_XTENSA_H_ */
static ALWAYS_INLINE void * atomic_ptr_set(atomic_ptr_t *target, void *value)
Implementation of atomic_ptr_set.
Definition atomic_xtensa.h:391
static ALWAYS_INLINE atomic_val_t atomic_inc(atomic_t *target)
Implementation of atomic_inc.
Definition atomic_xtensa.h:135
static ALWAYS_INLINE atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
Implementation of atomic_and.
Definition atomic_xtensa.h:216
static ALWAYS_INLINE atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
Implementation of atomic_sub.
Definition atomic_xtensa.h:114
static ALWAYS_INLINE atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
Implementation of atomic_set.
Definition atomic_xtensa.h:72
static ALWAYS_INLINE void * atomic_ptr_get(const atomic_ptr_t *target)
Implementation of atomic_ptr_get.
Definition atomic_xtensa.h:385
static ALWAYS_INLINE bool atomic_cas(atomic_t *target, atomic_val_t oldval, atomic_val_t newval)
Implementation of atomic_cas.
Definition atomic_xtensa.h:40
static ALWAYS_INLINE atomic_val_t atomic_get(const atomic_t *target)
Implementation of atomic_get.
Definition atomic_xtensa.h:21
static ALWAYS_INLINE atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
Implementation of atomic_add.
Definition atomic_xtensa.h:93
static ALWAYS_INLINE atomic_val_t atomic_clear(atomic_t *target)
Implementation of atomic_clear.
Definition atomic_xtensa.h:397
static ALWAYS_INLINE atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
Implementation of atomic_xor.
Definition atomic_xtensa.h:196
static ALWAYS_INLINE atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
Implementation of atomic_nand.
Definition atomic_xtensa.h:237
static ALWAYS_INLINE bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval)
Implementation of atomic_ptr_cas.
Definition atomic_xtensa.h:65
static ALWAYS_INLINE atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
Implementation of atomic_or.
Definition atomic_xtensa.h:176
static ALWAYS_INLINE atomic_val_t atomic_dec(atomic_t *target)
Implementation of atomic_dec.
Definition atomic_xtensa.h:156
static ALWAYS_INLINE void * atomic_ptr_clear(atomic_ptr_t *target)
Implementation of atomic_ptr_clear.
Definition atomic_xtensa.h:403
long atomic_t
Atomic integer variable.
Definition atomic_types.h:31
atomic_t atomic_val_t
Value type for atomic integer variables.
Definition atomic_types.h:38
void * atomic_ptr_t
Atomic pointer variable.
Definition atomic_types.h:46
#define ALWAYS_INLINE
Definition common.h:161
__UINT32_TYPE__ uint32_t
Definition stdint.h:90