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 40extern "C" { 41#endif /* __cplusplus */ 42#endif /* __cplusplus */ 43 44STATIC INLINE INT32 ArchAtomicRead(const Atomic *v) 45{ 46 INT32 val; 47 48 __asm__ __volatile__("l32ai %0, %1, 0\n" 49 : "=&a"(val) 50 : "a"(v) 51 : "memory"); 52 53 return val; 54} 55 56STATIC INLINE VOID ArchAtomicSet(Atomic *v, INT32 setVal) 57{ 58 INT32 val; 59 60 __asm__ __volatile__("1:l32ai %0, %2, 0\n" 61 " wsr %0, SCOMPARE1\n" 62 " s32c1i %3, %1\n" 63 " bne %3, %0, 1b" 64 : "=&a"(val), "+m"(*v) 65 : "a"(v), "a"(setVal) 66 : "memory"); 67} 68 69STATIC INLINE INT32 ArchAtomicAdd(Atomic *v, INT32 addVal) 70{ 71 INT32 val; 72 INT32 tmp; 73 74 __asm__ __volatile__("1:l32ai %0, %3, 0\n" 75 " wsr %0, SCOMPARE1\n" 76 " mov %1, %0\n" 77 " add %0, %0, %4\n" 78 " s32c1i %0, %2\n" 79 " bne %0, %1, 1b" 80 : "=&a"(val), "=&a"(tmp), "+m"(*v) 81 : "a"(v), "a"(addVal) 82 : "memory"); 83 84 return *v; 85} 86 87STATIC INLINE INT32 ArchAtomicSub(Atomic *v, INT32 subVal) 88{ 89 INT32 val; 90 INT32 tmp; 91 92 __asm__ __volatile__("1:l32ai %0, %3, 0\n" 93 " wsr %0, SCOMPARE1\n" 94 " mov %1, %0\n" 95 " sub %0, %0, %4\n" 96 " s32c1i %0, %2\n" 97 " bne %0, %1, 1b" 98 : "=&a"(val), "=&a"(tmp), "+m"(*v) 99 : "a"(v), "a"(subVal) 100 : "memory"); 101 return *v; 102} 103 104STATIC INLINE VOID ArchAtomicInc(Atomic *v) 105{ 106 (VOID)ArchAtomicAdd(v, 1); 107} 108 109STATIC INLINE VOID ArchAtomicDec(Atomic *v) 110{ 111 (VOID)ArchAtomicSub(v, 1); 112} 113 114STATIC INLINE INT32 ArchAtomicIncRet(Atomic *v) 115{ 116 return ArchAtomicAdd(v, 1); 117} 118 119STATIC INLINE INT32 ArchAtomicDecRet(Atomic *v) 120{ 121 return ArchAtomicSub(v, 1); 122} 123 124/** 125 * @ingroup los_arch_atomic 126 * @brief Atomic exchange for 32-bit variable. 127 * 128 * @par Description: 129 * This API is used to implement the atomic exchange for 32-bit variable 130 * and return the previous value of the atomic variable. 131 * @attention 132 * <ul>The pointer v must not be NULL.</ul> 133 * 134 * @param v [IN] The variable pointer. 135 * @param val [IN] The exchange value. 136 * 137 * @retval #INT32 The previous value of the atomic variable 138 * @par Dependency: 139 * <ul><li>los_arch_atomic.h: the header file that contains the API declaration.</li></ul> 140 * @see 141 */ 142STATIC INLINE INT32 ArchAtomicXchg32bits(volatile INT32 *v, INT32 val) 143{ 144 INT32 prevVal = 0; 145 INT32 tmp; 146 147 __asm__ __volatile__("1:l32ai %0, %3, 0\n" 148 " wsr %0, SCOMPARE1\n" 149 " mov %1, %0\n" 150 " s32c1i %4, %2\n" 151 " bne %4, %1, 1b" 152 : "=&a"(prevVal), "=&a"(tmp), "+m"(*v) 153 : "a"(v), "a"(val) 154 : "memory"); 155 156 return prevVal; 157} 158 159/** 160 * @ingroup los_arch_atomic 161 * @brief Atomic exchange for 32-bit variable with compare. 162 * 163 * @par Description: 164 * This API is used to implement the atomic exchange for 32-bit variable, if the value of variable is equal to oldVal. 165 * @attention 166 * <ul>The pointer v must not be NULL.</ul> 167 * 168 * @param v [IN] The variable pointer. 169 * @param val [IN] The new value. 170 * @param oldVal [IN] The old value. 171 * 172 * @retval TRUE The previous value of the atomic variable is not equal to oldVal. 173 * @retval FALSE The previous value of the atomic variable is equal to oldVal. 174 * @par Dependency: 175 * <ul><li>los_arch_atomic.h: the header file that contains the API declaration.</li></ul> 176 * @see 177 */ 178STATIC INLINE BOOL ArchAtomicCmpXchg32bits(volatile INT32 *v, INT32 val, INT32 oldVal) 179{ 180 INT32 prevVal = 0; 181 182 __asm__ __volatile__("l32ai %0, %2, 0\n" 183 "wsr %0, SCOMPARE1\n" 184 "bne %0, %3, 1f\n" 185 "s32c1i %4, %1\n" 186 "1:" 187 : "=&a"(prevVal), "+m"(*v) 188 : "a"(v), "a"(oldVal), "a"(val) 189 : "cc"); 190 191 return prevVal != oldVal; 192} 193 194STATIC INLINE INT64 ArchAtomic64Read(const Atomic64 *v) 195{ 196 INT64 val; 197 UINT32 intSave; 198 199 intSave = LOS_IntLock(); 200 val = *v; 201 LOS_IntRestore(intSave); 202 203 return val; 204} 205 206STATIC INLINE VOID ArchAtomic64Set(Atomic64 *v, INT64 setVal) 207{ 208 UINT32 intSave; 209 210 intSave = LOS_IntLock(); 211 *v = setVal; 212 LOS_IntRestore(intSave); 213} 214 215STATIC INLINE INT64 ArchAtomic64Add(Atomic64 *v, INT64 addVal) 216{ 217 INT64 val; 218 UINT32 intSave; 219 220 intSave = LOS_IntLock(); 221 *v += addVal; 222 val = *v; 223 LOS_IntRestore(intSave); 224 225 return val; 226} 227 228STATIC INLINE INT64 ArchAtomic64Sub(Atomic64 *v, INT64 subVal) 229{ 230 INT64 val; 231 UINT32 intSave; 232 233 intSave = LOS_IntLock(); 234 *v -= subVal; 235 val = *v; 236 LOS_IntRestore(intSave); 237 238 return val; 239} 240 241STATIC INLINE VOID ArchAtomic64Inc(Atomic64 *v) 242{ 243 (VOID)ArchAtomic64Add(v, 1); 244} 245 246STATIC INLINE INT64 ArchAtomic64IncRet(Atomic64 *v) 247{ 248 return ArchAtomic64Add(v, 1); 249} 250 251STATIC INLINE VOID ArchAtomic64Dec(Atomic64 *v) 252{ 253 (VOID)ArchAtomic64Sub(v, 1); 254} 255 256STATIC INLINE INT64 ArchAtomic64DecRet(Atomic64 *v) 257{ 258 return ArchAtomic64Sub(v, 1); 259} 260 261STATIC INLINE INT64 ArchAtomicXchg64bits(Atomic64 *v, INT64 val) 262{ 263 INT64 prevVal; 264 UINT32 intSave; 265 266 intSave = LOS_IntLock(); 267 prevVal = *v; 268 *v = val; 269 LOS_IntRestore(intSave); 270 271 return prevVal; 272} 273 274STATIC INLINE BOOL ArchAtomicCmpXchg64bits(Atomic64 *v, INT64 val, INT64 oldVal) 275{ 276 INT64 prevVal; 277 UINT32 intSave; 278 279 intSave = LOS_IntLock(); 280 prevVal = *v; 281 if (prevVal == oldVal) { 282 *v = val; 283 } 284 LOS_IntRestore(intSave); 285 286 return prevVal != oldVal; 287} 288 289#ifdef __cplusplus 290#if __cplusplus 291} 292#endif /* __cplusplus */ 293#endif /* __cplusplus */ 294 295#endif /* _LOS_ARCH_ATOMIC_H */ 296