1 /*
2  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *    * Redistributions of source code must retain the above copyright
8  *      notice, this list of conditions and the following disclaimer.
9  *    * Redistributions in binary form must reproduce the above
10  *      copyright notice, this list of conditions and the following
11  *      disclaimer in the documentation and/or other materials provided
12  *      with the distribution.
13  *    * Neither the name of The Linux Foundation nor the names of its
14  *      contributors may be used to endorse or promote products derived
15  *      from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 #include "AEEatomic.h"
30 
31 #ifdef _WIN32
32 #include "Windows.h"
atomic_CompareAndExchange(uint32 * volatile puDest,uint32 uExchange,uint32 uCompare)33 uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare) {
34    C_ASSERT(sizeof(LONG) == sizeof(uint32));
35    return (uint32)InterlockedCompareExchange((LONG*)puDest, (LONG)uExchange, (LONG)uCompare);
36 }
atomic_CompareAndExchangeUP(uintptr_t * volatile puDest,uintptr_t uExchange,uintptr_t uCompare)37 uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare) {
38    C_ASSERT(sizeof(uintptr_t) == sizeof(void*));
39    return (uintptr_t)InterlockedCompareExchangePointer((void**)puDest, (void*)uExchange, (void*)uCompare);
40 }
41 #elif __hexagon__
42 
43 #ifndef C_ASSERT
44 #define C_ASSERT(test) \
45     switch(0) {\
46       case 0:\
47       case test:;\
48     }
49 #endif
50 
51 static inline unsigned int
qurt_atomic_compare_val_and_set(unsigned int * target,unsigned int old_val,unsigned int new_val)52 qurt_atomic_compare_val_and_set(unsigned int* target,
53                                 unsigned int old_val,
54                                 unsigned int new_val)
55 {
56    unsigned int current_val;
57 
58    __asm__ __volatile__(
59        "1:     %0 = memw_locked(%2)\n"
60        "       p0 = cmp.eq(%0, %3)\n"
61        "       if !p0 jump 2f\n"
62        "       memw_locked(%2, p0) = %4\n"
63        "       if !p0 jump 1b\n"
64        "2:\n"
65        : "=&r" (current_val),"+m" (*target)
66        : "r" (target), "r" (old_val), "r" (new_val)
67        : "p0");
68 
69    return current_val;
70 }
atomic_CompareAndExchange(uint32 * volatile puDest,uint32 uExchange,uint32 uCompare)71 uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare) {
72    return (uint32)qurt_atomic_compare_val_and_set((unsigned int*)puDest, uCompare, uExchange);
73 }
atomic_CompareAndExchangeUP(uintptr_t * volatile puDest,uintptr_t uExchange,uintptr_t uCompare)74 uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare) {
75    C_ASSERT(sizeof(uintptr_t) == sizeof(uint32));
76    return (uint32)atomic_CompareAndExchange((uint32*)puDest, (uint32)uExchange, (uint32)uCompare);
77 }
78 #elif __GNUC__
atomic_CompareAndExchange(uint32 * volatile puDest,uint32 uExchange,uint32 uCompare)79 uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare) {
80    return __sync_val_compare_and_swap(puDest, uCompare, uExchange);
81 }
atomic_CompareAndExchange64(uint64 * volatile puDest,uint64 uExchange,uint64 uCompare)82 uint64 atomic_CompareAndExchange64(uint64 * volatile puDest, uint64 uExchange, uint64 uCompare) {
83    return __sync_val_compare_and_swap(puDest, uCompare, uExchange);
84 }
atomic_CompareAndExchangeUP(uintptr_t * volatile puDest,uintptr_t uExchange,uintptr_t uCompare)85 uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare) {
86    return __sync_val_compare_and_swap(puDest, uCompare, uExchange);
87 }
88 #endif //compare and exchange
89