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_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 uint32_t v = newval;
61
62 /* Read from address and mark it for exclusive access. */
63 __asm__ volatile("l32ex %0, %1" : "=r"(mem_val) : "r"(addr));
64
65 if (mem_val == oldval) {
66 uint32_t result;
67
68 __asm__ volatile("s32ex %1, %2; getex %0" : "=r"(result), "+r"(v) : "r"(addr));
69
70 /* If GETEX returns store successful, we return the old value.
71 * Otherwise, we must return some other value to signal that
72 * the store failed to function caller.
73 */
74 return (result == 1U) ? oldval : newval;
75 }
76
77 /* Since *addr != oldval, we skip writing to memory and
78 * need to remove the exclusive lock before returning.
79 */
80 __asm__("clrex");
81
82 return newval;
83}
84
85#elif XCHAL_HAVE_S32C1I
86
87/*
88 * This utilizes SCOMPARE1 register and s32c1i instruction to
89 * perform compare-and-set atomic operation. This will
90 * unconditionally read from the atomic variable at @p addr
91 * before the comparison. This value is returned from
92 * the function.
93 */
94static ALWAYS_INLINE
96 atomic_val_t newval)
97{
98 __asm__ volatile("wsr %1, SCOMPARE1; s32c1i %0, %2, 0"
99 : "+r"(newval), "+r"(oldval) : "r"(addr) : "memory");
100
101 return newval; /* got swapped with the old memory by s32c1i */
102}
103
104#else
105#error "No available hardware support for atomic operations"
106#endif
107
109static ALWAYS_INLINE
110bool atomic_cas(atomic_t *target, atomic_val_t oldval, atomic_val_t newval)
111{
112 return oldval == xtensa_cas(target, oldval, newval);
113}
114
116static ALWAYS_INLINE
117bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval)
118{
119 return (atomic_val_t) oldval
120 == xtensa_cas((atomic_t *) target, (atomic_val_t) oldval,
121 (atomic_val_t) newval);
122}
123
124/* Generates an atomic exchange sequence that swaps the value at
125 * address "target", whose old value is read to be "cur", with the
126 * specified expression. Evaluates to the old value which was
127 * atomically replaced.
128 */
129#define Z__GEN_ATOMXCHG(expr) ({ \
130 atomic_val_t res, cur; \
131 do { \
132 cur = *target; \
133 res = xtensa_cas(target, cur, (expr)); \
134 } while (res != cur); \
135 res; })
136
138static ALWAYS_INLINE
140{
141 return Z__GEN_ATOMXCHG(value);
142}
143
145static ALWAYS_INLINE
147{
148 return Z__GEN_ATOMXCHG(cur + value);
149}
150
152static ALWAYS_INLINE
154{
155 return Z__GEN_ATOMXCHG(cur - value);
156}
157
159static ALWAYS_INLINE
161{
162 return Z__GEN_ATOMXCHG(cur + 1);
163}
164
166static ALWAYS_INLINE
168{
169 return Z__GEN_ATOMXCHG(cur - 1);
170}
171
174 atomic_val_t value)
175{
176 return Z__GEN_ATOMXCHG(cur | value);
177}
178
181 atomic_val_t value)
182{
183 return Z__GEN_ATOMXCHG(cur ^ value);
184}
185
188 atomic_val_t value)
189{
190 return Z__GEN_ATOMXCHG(cur & value);
191}
192
195 atomic_val_t value)
196{
197 return Z__GEN_ATOMXCHG(~(cur & value));
198}
199
201static ALWAYS_INLINE void *atomic_ptr_get(const atomic_ptr_t *target)
202{
203 return (void *) atomic_get((atomic_t *)target);
204}
205
207static ALWAYS_INLINE void *atomic_ptr_set(atomic_ptr_t *target, void *value)
208{
209 return (void *) atomic_set((atomic_t *) target, (atomic_val_t) value);
210}
211
214{
215 return atomic_set(target, 0);
216}
217
220{
221 return (void *) atomic_set((atomic_t *) target, 0);
222}
223
224#endif /* ZEPHYR_INCLUDE_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:207
static ALWAYS_INLINE atomic_val_t atomic_inc(atomic_t *target)
Implementation of atomic_inc.
Definition atomic_xtensa.h:160
static ALWAYS_INLINE atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
Implementation of atomic_and.
Definition atomic_xtensa.h:187
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:153
static ALWAYS_INLINE atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
Implementation of atomic_set.
Definition atomic_xtensa.h:139
static ALWAYS_INLINE void * atomic_ptr_get(const atomic_ptr_t *target)
Implementation of atomic_ptr_get.
Definition atomic_xtensa.h:201
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:110
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:146
static ALWAYS_INLINE atomic_val_t atomic_clear(atomic_t *target)
Implementation of atomic_clear.
Definition atomic_xtensa.h:213
static ALWAYS_INLINE atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
Implementation of atomic_xor.
Definition atomic_xtensa.h:180
static ALWAYS_INLINE atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
Implementation of atomic_nand.
Definition atomic_xtensa.h:194
static ALWAYS_INLINE bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval)
Implementation of atomic_ptr_cas.
Definition atomic_xtensa.h:117
static ALWAYS_INLINE atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
Implementation of atomic_or.
Definition atomic_xtensa.h:173
static ALWAYS_INLINE atomic_val_t atomic_dec(atomic_t *target)
Implementation of atomic_dec.
Definition atomic_xtensa.h:167
static ALWAYS_INLINE void * atomic_ptr_clear(atomic_ptr_t *target)
Implementation of atomic_ptr_clear.
Definition atomic_xtensa.h:219
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