Zephyr API Documentation 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_ATOMIC_XTENSA_H_
7#define ZEPHYR_INCLUDE_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 define an inline implementation here for atomic CAS.
17 */
18
21{
22 atomic_val_t ret;
23
24 /* Actual Xtensa hardware seems to have only in-order
25 * pipelines, but the architecture does define a barrier load,
26 * so use it. There is a matching s32ri instruction, but
27 * nothing in the Zephyr API requires a barrier store (all the
28 * atomic write ops have exchange semantics.
29 */
30 __asm__ volatile("l32ai %0, %1, 0"
31 : "=r"(ret) : "r"(target) : "memory");
32 return ret;
33}
34
47
48#if XCHAL_HAVE_EXCLUSIVE || defined(__DOXYGEN__)
49
50/*
51 * This utilizes L32EX/S32EX instructions to perform compare-and-set atomic
52 * operation. This will unconditionally read from the atomic variable at @p addr
53 * before the comparison. This value is returned from the function.
54 */
55static ALWAYS_INLINE
57 atomic_val_t newval)
58{
59 atomic_val_t mem_val;
60
61 /* Read from address and mark it for exclusive access. */
62 __asm__ volatile("l32ex %0, %1" : "=r"(mem_val) : "r"(addr));
63
64 if (mem_val == oldval) {
65 uint32_t result;
66
67 __asm__ volatile("s32ex %1, %2; getex %0" : "=r"(result) : "r"(newval), "r"(addr));
68
69 /* If GETEX returns store successful, we return the old value.
70 * Otherwise, we must return some other value to signal that
71 * the store failed to function caller.
72 */
73 return (result == 1U) ? oldval : ~oldval;
74 }
75
76 /* Since *addr != oldval, we skip writing to memory and
77 * need to remove the exclusive lock before returning.
78 */
79 __asm__("clrex");
80
81 return mem_val;
82}
83
84#elif XCHAL_HAVE_S32C1I
85
86/*
87 * This utilizes SCOMPARE1 register and s32c1i instruction to
88 * perform compare-and-set atomic operation. This will
89 * unconditionally read from the atomic variable at @p addr
90 * before the comparison. This value is returned from
91 * the function.
92 */
93static ALWAYS_INLINE
95 atomic_val_t newval)
96{
97 __asm__ volatile("wsr %1, SCOMPARE1; s32c1i %0, %2, 0"
98 : "+r"(newval), "+r"(oldval) : "r"(addr) : "memory");
99
100 return newval; /* got swapped with the old memory by s32c1i */
101}
102
103#else
104#error "No available hardware support for atomic operations"
105#endif
106
108static ALWAYS_INLINE
109bool atomic_cas(atomic_t *target, atomic_val_t oldval, atomic_val_t newval)
110{
111 return oldval == xtensa_cas(target, oldval, newval);
112}
113
115static ALWAYS_INLINE
116bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval)
117{
118 return (atomic_val_t) oldval
119 == xtensa_cas((atomic_t *) target, (atomic_val_t) oldval,
120 (atomic_val_t) newval);
121}
122
123/* Generates an atomic exchange sequence that swaps the value at
124 * address "target", whose old value is read to be "cur", with the
125 * specified expression. Evaluates to the old value which was
126 * atomically replaced.
127 */
128#define Z__GEN_ATOMXCHG(expr) ({ \
129 atomic_val_t res, cur; \
130 do { \
131 cur = *target; \
132 res = xtensa_cas(target, cur, (expr)); \
133 } while (res != cur); \
134 res; })
135
137static ALWAYS_INLINE
139{
140 return Z__GEN_ATOMXCHG(value);
141}
142
144static ALWAYS_INLINE
146{
147 return Z__GEN_ATOMXCHG(cur + value);
148}
149
151static ALWAYS_INLINE
153{
154 return Z__GEN_ATOMXCHG(cur - value);
155}
156
158static ALWAYS_INLINE
160{
161 return Z__GEN_ATOMXCHG(cur + 1);
162}
163
165static ALWAYS_INLINE
167{
168 return Z__GEN_ATOMXCHG(cur - 1);
169}
170
173 atomic_val_t value)
174{
175 return Z__GEN_ATOMXCHG(cur | value);
176}
177
180 atomic_val_t value)
181{
182 return Z__GEN_ATOMXCHG(cur ^ value);
183}
184
187 atomic_val_t value)
188{
189 return Z__GEN_ATOMXCHG(cur & value);
190}
191
194 atomic_val_t value)
195{
196 return Z__GEN_ATOMXCHG(~(cur & value));
197}
198
200static ALWAYS_INLINE void *atomic_ptr_get(const atomic_ptr_t *target)
201{
202 return (void *) atomic_get((atomic_t *)target);
203}
204
206static ALWAYS_INLINE void *atomic_ptr_set(atomic_ptr_t *target, void *value)
207{
208 return (void *) atomic_set((atomic_t *) target, (atomic_val_t) value);
209}
210
213{
214 return atomic_set(target, 0);
215}
216
219{
220 return (void *) atomic_set((atomic_t *) target, 0);
221}
222
223#endif /* ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_ */
long atomic_t
Definition atomic_types.h:15
atomic_t atomic_val_t
Definition atomic_types.h:16
void * atomic_ptr_t
Definition atomic_types.h:17
static ALWAYS_INLINE void * atomic_ptr_set(atomic_ptr_t *target, void *value)
Implementation of atomic_ptr_set.
Definition atomic_xtensa.h:206
static ALWAYS_INLINE atomic_val_t atomic_inc(atomic_t *target)
Implementation of atomic_inc.
Definition atomic_xtensa.h:159
static ALWAYS_INLINE atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
Implementation of atomic_and.
Definition atomic_xtensa.h:186
static ALWAYS_INLINE atomic_val_t xtensa_cas(atomic_t *addr, atomic_val_t oldval, atomic_val_t newval)
Xtensa specific atomic compare-and-set (CAS).
Definition atomic_xtensa.h:56
static ALWAYS_INLINE atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
Implementation of atomic_sub.
Definition atomic_xtensa.h:152
static ALWAYS_INLINE atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
Implementation of atomic_set.
Definition atomic_xtensa.h:138
static ALWAYS_INLINE void * atomic_ptr_get(const atomic_ptr_t *target)
Implementation of atomic_ptr_get.
Definition atomic_xtensa.h:200
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:109
static ALWAYS_INLINE atomic_val_t atomic_get(const atomic_t *target)
Implementation of atomic_get.
Definition atomic_xtensa.h:20
static ALWAYS_INLINE atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
Implementation of atomic_add.
Definition atomic_xtensa.h:145
static ALWAYS_INLINE atomic_val_t atomic_clear(atomic_t *target)
Implementation of atomic_clear.
Definition atomic_xtensa.h:212
static ALWAYS_INLINE atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
Implementation of atomic_xor.
Definition atomic_xtensa.h:179
static ALWAYS_INLINE atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
Implementation of atomic_nand.
Definition atomic_xtensa.h:193
static ALWAYS_INLINE bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval)
Implementation of atomic_ptr_cas.
Definition atomic_xtensa.h:116
static ALWAYS_INLINE atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
Implementation of atomic_or.
Definition atomic_xtensa.h:172
static ALWAYS_INLINE atomic_val_t atomic_dec(atomic_t *target)
Implementation of atomic_dec.
Definition atomic_xtensa.h:166
static ALWAYS_INLINE void * atomic_ptr_clear(atomic_ptr_t *target)
Implementation of atomic_ptr_clear.
Definition atomic_xtensa.h:218
#define ALWAYS_INLINE
Definition common.h:161
__UINT32_TYPE__ uint32_t
Definition stdint.h:90