GNU Linux-libre 4.19.211-gnu1
[releases.git] / tools / arch / x86 / include / asm / cmpxchg.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef TOOLS_ASM_X86_CMPXCHG_H
3 #define TOOLS_ASM_X86_CMPXCHG_H
4
5 #include <linux/compiler.h>
6
7 /*
8  * Non-existant functions to indicate usage errors at link time
9  * (or compile-time if the compiler implements __compiletime_error().
10  */
11 extern void __cmpxchg_wrong_size(void)
12         __compiletime_error("Bad argument size for cmpxchg");
13
14 /*
15  * Constants for operation sizes. On 32-bit, the 64-bit size it set to
16  * -1 because sizeof will never return -1, thereby making those switch
17  * case statements guaranteeed dead code which the compiler will
18  * eliminate, and allowing the "missing symbol in the default case" to
19  * indicate a usage error.
20  */
21 #define __X86_CASE_B    1
22 #define __X86_CASE_W    2
23 #define __X86_CASE_L    4
24 #ifdef __x86_64__
25 #define __X86_CASE_Q    8
26 #else
27 #define __X86_CASE_Q    -1              /* sizeof will never return -1 */
28 #endif
29
30 /*
31  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
32  * store NEW in MEM.  Return the initial value in MEM.  Success is
33  * indicated by comparing RETURN with OLD.
34  */
35 #define __raw_cmpxchg(ptr, old, new, size, lock)                        \
36 ({                                                                      \
37         __typeof__(*(ptr)) __ret;                                       \
38         __typeof__(*(ptr)) __old = (old);                               \
39         __typeof__(*(ptr)) __new = (new);                               \
40         switch (size) {                                                 \
41         case __X86_CASE_B:                                              \
42         {                                                               \
43                 volatile u8 *__ptr = (volatile u8 *)(ptr);              \
44                 asm volatile(lock "cmpxchgb %2,%1"                      \
45                              : "=a" (__ret), "+m" (*__ptr)              \
46                              : "q" (__new), "0" (__old)                 \
47                              : "memory");                               \
48                 break;                                                  \
49         }                                                               \
50         case __X86_CASE_W:                                              \
51         {                                                               \
52                 volatile u16 *__ptr = (volatile u16 *)(ptr);            \
53                 asm volatile(lock "cmpxchgw %2,%1"                      \
54                              : "=a" (__ret), "+m" (*__ptr)              \
55                              : "r" (__new), "0" (__old)                 \
56                              : "memory");                               \
57                 break;                                                  \
58         }                                                               \
59         case __X86_CASE_L:                                              \
60         {                                                               \
61                 volatile u32 *__ptr = (volatile u32 *)(ptr);            \
62                 asm volatile(lock "cmpxchgl %2,%1"                      \
63                              : "=a" (__ret), "+m" (*__ptr)              \
64                              : "r" (__new), "0" (__old)                 \
65                              : "memory");                               \
66                 break;                                                  \
67         }                                                               \
68         case __X86_CASE_Q:                                              \
69         {                                                               \
70                 volatile u64 *__ptr = (volatile u64 *)(ptr);            \
71                 asm volatile(lock "cmpxchgq %2,%1"                      \
72                              : "=a" (__ret), "+m" (*__ptr)              \
73                              : "r" (__new), "0" (__old)                 \
74                              : "memory");                               \
75                 break;                                                  \
76         }                                                               \
77         default:                                                        \
78                 __cmpxchg_wrong_size();                                 \
79         }                                                               \
80         __ret;                                                          \
81 })
82
83 #define __cmpxchg(ptr, old, new, size)                                  \
84         __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
85
86 #define cmpxchg(ptr, old, new)                                          \
87         __cmpxchg(ptr, old, new, sizeof(*(ptr)))
88
89
90 #endif  /* TOOLS_ASM_X86_CMPXCHG_H */