1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifndef _LOS_ARCH_ATOMIC_H
33 #define _LOS_ARCH_ATOMIC_H
34
35 #include "los_compiler.h"
36 #include "los_interrupt.h"
37
38 #ifdef __cplusplus
39 #if __cplusplus
40 extern "C" {
41 #endif /* __cplusplus */
42 #endif /* __cplusplus */
43
ArchAtomicRead(const Atomic * v)44 STATIC INLINE INT32 ArchAtomicRead(const Atomic *v)
45 {
46 INT32 val;
47 UINT32 intSave;
48
49 intSave = LOS_IntLock();
50
51 __asm__ __volatile__("lr.w %0, (%1)\n"
52 "fence rw, rw\n"
53 : "=&r"(val)
54 : "r"(v)
55 : "memory");
56 LOS_IntRestore(intSave);
57
58 return val;
59 }
60
ArchAtomicSet(Atomic * v,INT32 setVal)61 STATIC INLINE VOID ArchAtomicSet(Atomic *v, INT32 setVal)
62 {
63 UINT32 prevVal;
64 UINT32 intSave;
65
66 intSave = LOS_IntLock();
67
68 __asm__ __volatile__("amoswap.w %0, %2, (%1)\n"
69 : "=r"(prevVal)
70 : "r"(v), "r"(setVal)
71 : "memory");
72 LOS_IntRestore(intSave);
73 }
74
ArchAtomicAdd(Atomic * v,INT32 addVal)75 STATIC INLINE INT32 ArchAtomicAdd(Atomic *v, INT32 addVal)
76 {
77 INT32 val;
78 UINT32 intSave;
79
80 intSave = LOS_IntLock();
81
82 __asm__ __volatile__("amoadd.w %0, %2, (%1)\n"
83 "lw %0, (%1)\n"
84 "fence rw, rw\n"
85 : "=&r"(val)
86 : "r"(v), "r"(addVal)
87 : "memory");
88 LOS_IntRestore(intSave);
89
90 return val;
91 }
92
ArchAtomicSub(Atomic * v,INT32 subVal)93 STATIC INLINE INT32 ArchAtomicSub(Atomic *v, INT32 subVal)
94 {
95 INT32 val;
96 UINT32 intSave;
97
98 intSave = LOS_IntLock();
99
100 __asm__ __volatile__("amoadd.w %0, %2, (%1)\n"
101 "lw %0, (%1)\n"
102 "fence rw, rw\n"
103 : "=&r"(val)
104 : "r"(v), "r"(-subVal)
105 : "memory");
106 LOS_IntRestore(intSave);
107
108 return val;
109 }
110
ArchAtomicInc(Atomic * v)111 STATIC INLINE VOID ArchAtomicInc(Atomic *v)
112 {
113 (VOID)ArchAtomicAdd(v, 1);
114 }
115
ArchAtomicDec(Atomic * v)116 STATIC INLINE VOID ArchAtomicDec(Atomic *v)
117 {
118 (VOID)ArchAtomicSub(v, 1);
119 }
120
ArchAtomicIncRet(Atomic * v)121 STATIC INLINE INT32 ArchAtomicIncRet(Atomic *v)
122 {
123 return ArchAtomicAdd(v, 1);
124 }
125
ArchAtomicDecRet(Atomic * v)126 STATIC INLINE INT32 ArchAtomicDecRet(Atomic *v)
127 {
128 return ArchAtomicSub(v, 1);
129 }
130
131 /**
132 * @ingroup los_arch_atomic
133 * @brief Atomic exchange for 32-bit variable.
134 *
135 * @par Description:
136 * This API is used to implement the atomic exchange for 32-bit variable
137 * and return the previous value of the atomic variable.
138 * @attention
139 * <ul>The pointer v must not be NULL.</ul>
140 *
141 * @param v [IN] The variable pointer.
142 * @param val [IN] The exchange value.
143 *
144 * @retval #INT32 The previous value of the atomic variable
145 * @par Dependency:
146 * <ul><li>los_arch_atomic.h: the header file that contains the API declaration.</li></ul>
147 * @see
148 */
ArchAtomicXchg32bits(volatile INT32 * v,INT32 val)149 STATIC INLINE INT32 ArchAtomicXchg32bits(volatile INT32 *v, INT32 val)
150 {
151 INT32 prevVal = 0;
152 UINT32 intSave;
153
154 intSave = LOS_IntLock();
155
156 __asm__ __volatile__("lw %0, 0(%1)\n"
157 "amoswap.w %0, %2, (%1)\n"
158 : "=&r"(prevVal)
159 : "r"(v), "r"(val)
160 : "memory");
161 LOS_IntRestore(intSave);
162
163 return prevVal;
164 }
165
166 /**
167 * @ingroup los_arch_atomic
168 * @brief Atomic exchange for 32-bit variable with compare.
169 *
170 * @par Description:
171 * This API is used to implement the atomic exchange for 32-bit variable, if the value of variable is equal to oldVal.
172 * @attention
173 * <ul>The pointer v must not be NULL.</ul>
174 *
175 * @param v [IN] The variable pointer.
176 * @param val [IN] The new value.
177 * @param oldVal [IN] The old value.
178 *
179 * @retval TRUE The previous value of the atomic variable is not equal to oldVal.
180 * @retval FALSE The previous value of the atomic variable is equal to oldVal.
181 * @par Dependency:
182 * <ul><li>los_arch_atomic.h: the header file that contains the API declaration.</li></ul>
183 * @see
184 */
ArchAtomicCmpXchg32bits(volatile INT32 * v,INT32 val,INT32 oldVal)185 STATIC INLINE BOOL ArchAtomicCmpXchg32bits(volatile INT32 *v, INT32 val, INT32 oldVal)
186 {
187 INT32 prevVal = 0;
188 UINT32 intSave;
189
190 intSave = LOS_IntLock();
191 __asm__ __volatile__("lw %0, 0(%1)\n"
192 "bne %0, %2, 1f\n"
193 "amoswap.w %0, %3, (%1)\n"
194 "1:"
195 : "=&r"(prevVal)
196 : "r"(v), "r"(oldVal), "r"(val)
197 : "memory");
198 LOS_IntRestore(intSave);
199
200 return prevVal != oldVal;
201 }
202
ArchAtomic64Read(const Atomic64 * v)203 STATIC INLINE INT64 ArchAtomic64Read(const Atomic64 *v)
204 {
205 INT64 val;
206 UINT32 intSave;
207
208 intSave = LOS_IntLock();
209 val = *v;
210 LOS_IntRestore(intSave);
211
212 return val;
213 }
214
ArchAtomic64Set(Atomic64 * v,INT64 setVal)215 STATIC INLINE VOID ArchAtomic64Set(Atomic64 *v, INT64 setVal)
216 {
217 UINT32 intSave;
218
219 intSave = LOS_IntLock();
220 *v = setVal;
221 LOS_IntRestore(intSave);
222 }
223
ArchAtomic64Add(Atomic64 * v,INT64 addVal)224 STATIC INLINE INT64 ArchAtomic64Add(Atomic64 *v, INT64 addVal)
225 {
226 INT64 val;
227 UINT32 intSave;
228
229 intSave = LOS_IntLock();
230 *v += addVal;
231 val = *v;
232 LOS_IntRestore(intSave);
233
234 return val;
235 }
236
ArchAtomic64Sub(Atomic64 * v,INT64 subVal)237 STATIC INLINE INT64 ArchAtomic64Sub(Atomic64 *v, INT64 subVal)
238 {
239 INT64 val;
240 UINT32 intSave;
241
242 intSave = LOS_IntLock();
243 *v -= subVal;
244 val = *v;
245 LOS_IntRestore(intSave);
246
247 return val;
248 }
249
ArchAtomic64Inc(Atomic64 * v)250 STATIC INLINE VOID ArchAtomic64Inc(Atomic64 *v)
251 {
252 (VOID)ArchAtomic64Add(v, 1);
253 }
254
ArchAtomic64IncRet(Atomic64 * v)255 STATIC INLINE INT64 ArchAtomic64IncRet(Atomic64 *v)
256 {
257 return ArchAtomic64Add(v, 1);
258 }
259
ArchAtomic64Dec(Atomic64 * v)260 STATIC INLINE VOID ArchAtomic64Dec(Atomic64 *v)
261 {
262 (VOID)ArchAtomic64Sub(v, 1);
263 }
264
ArchAtomic64DecRet(Atomic64 * v)265 STATIC INLINE INT64 ArchAtomic64DecRet(Atomic64 *v)
266 {
267 return ArchAtomic64Sub(v, 1);
268 }
269
ArchAtomicXchg64bits(Atomic64 * v,INT64 val)270 STATIC INLINE INT64 ArchAtomicXchg64bits(Atomic64 *v, INT64 val)
271 {
272 INT64 prevVal;
273 UINT32 intSave;
274
275 intSave = LOS_IntLock();
276 prevVal = *v;
277 *v = val;
278 LOS_IntRestore(intSave);
279
280 return prevVal;
281 }
282
ArchAtomicCmpXchg64bits(Atomic64 * v,INT64 val,INT64 oldVal)283 STATIC INLINE BOOL ArchAtomicCmpXchg64bits(Atomic64 *v, INT64 val, INT64 oldVal)
284 {
285 INT64 prevVal;
286 UINT32 intSave;
287
288 intSave = LOS_IntLock();
289 prevVal = *v;
290 if (prevVal == oldVal) {
291 *v = val;
292 }
293 LOS_IntRestore(intSave);
294
295 return prevVal != oldVal;
296 }
297
298 #ifdef __cplusplus
299 #if __cplusplus
300 }
301 #endif /* __cplusplus */
302 #endif /* __cplusplus */
303
304 #endif /* _LOS_ARCH_ATOMIC_H */
305