xref: /linux/arch/riscv/include/asm/cmpxchg.h (revision 9a379e77033f02c4a071891afdf0f0a01eff8ccb)
1 /*
2  * Copyright (C) 2014 Regents of the University of California
3  *
4  *   This program is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation, version 2.
7  *
8  *   This program is distributed in the hope that it will be useful,
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *   GNU General Public License for more details.
12  */
13 
14 #ifndef _ASM_RISCV_CMPXCHG_H
15 #define _ASM_RISCV_CMPXCHG_H
16 
17 #include <linux/bug.h>
18 
19 #include <asm/barrier.h>
20 
21 #define __xchg(new, ptr, size, asm_or)				\
22 ({								\
23 	__typeof__(ptr) __ptr = (ptr);				\
24 	__typeof__(new) __new = (new);				\
25 	__typeof__(*(ptr)) __ret;				\
26 	switch (size) {						\
27 	case 4:							\
28 		__asm__ __volatile__ (				\
29 			"amoswap.w" #asm_or " %0, %2, %1"	\
30 			: "=r" (__ret), "+A" (*__ptr)		\
31 			: "r" (__new)				\
32 			: "memory");				\
33 		break;						\
34 	case 8:							\
35 		__asm__ __volatile__ (				\
36 			"amoswap.d" #asm_or " %0, %2, %1"	\
37 			: "=r" (__ret), "+A" (*__ptr)		\
38 			: "r" (__new)				\
39 			: "memory");				\
40 		break;						\
41 	default:						\
42 		BUILD_BUG();					\
43 	}							\
44 	__ret;							\
45 })
46 
47 #define xchg(ptr, x)    (__xchg((x), (ptr), sizeof(*(ptr)), .aqrl))
48 
49 #define xchg32(ptr, x)				\
50 ({						\
51 	BUILD_BUG_ON(sizeof(*(ptr)) != 4);	\
52 	xchg((ptr), (x));			\
53 })
54 
55 #define xchg64(ptr, x)				\
56 ({						\
57 	BUILD_BUG_ON(sizeof(*(ptr)) != 8);	\
58 	xchg((ptr), (x));			\
59 })
60 
61 /*
62  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
63  * store NEW in MEM.  Return the initial value in MEM.  Success is
64  * indicated by comparing RETURN with OLD.
65  */
66 #define __cmpxchg(ptr, old, new, size, lrb, scb)			\
67 ({									\
68 	__typeof__(ptr) __ptr = (ptr);					\
69 	__typeof__(*(ptr)) __old = (old);				\
70 	__typeof__(*(ptr)) __new = (new);				\
71 	__typeof__(*(ptr)) __ret;					\
72 	register unsigned int __rc;					\
73 	switch (size) {							\
74 	case 4:								\
75 		__asm__ __volatile__ (					\
76 		"0:"							\
77 			"lr.w" #scb " %0, %2\n"				\
78 			"bne         %0, %z3, 1f\n"			\
79 			"sc.w" #lrb " %1, %z4, %2\n"			\
80 			"bnez        %1, 0b\n"				\
81 		"1:"							\
82 			: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)	\
83 			: "rJ" (__old), "rJ" (__new)			\
84 			: "memory");					\
85 		break;							\
86 	case 8:								\
87 		__asm__ __volatile__ (					\
88 		"0:"							\
89 			"lr.d" #scb " %0, %2\n"				\
90 			"bne         %0, %z3, 1f\n"			\
91 			"sc.d" #lrb " %1, %z4, %2\n"			\
92 			"bnez        %1, 0b\n"				\
93 		"1:"							\
94 			: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)	\
95 			: "rJ" (__old), "rJ" (__new)			\
96 			: "memory");					\
97 		break;							\
98 	default:							\
99 		BUILD_BUG();						\
100 	}								\
101 	__ret;								\
102 })
103 
104 #define cmpxchg(ptr, o, n) \
105 	(__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), .aqrl, .aqrl))
106 
107 #define cmpxchg_local(ptr, o, n) \
108 	(__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), , ))
109 
110 #define cmpxchg32(ptr, o, n)			\
111 ({						\
112 	BUILD_BUG_ON(sizeof(*(ptr)) != 4);	\
113 	cmpxchg((ptr), (o), (n));		\
114 })
115 
116 #define cmpxchg32_local(ptr, o, n)		\
117 ({						\
118 	BUILD_BUG_ON(sizeof(*(ptr)) != 4);	\
119 	cmpxchg_local((ptr), (o), (n));		\
120 })
121 
122 #define cmpxchg64(ptr, o, n)			\
123 ({						\
124 	BUILD_BUG_ON(sizeof(*(ptr)) != 8);	\
125 	cmpxchg((ptr), (o), (n));		\
126 })
127 
128 #define cmpxchg64_local(ptr, o, n)		\
129 ({						\
130 	BUILD_BUG_ON(sizeof(*(ptr)) != 8);	\
131 	cmpxchg_local((ptr), (o), (n));		\
132 })
133 
134 #endif /* _ASM_RISCV_CMPXCHG_H */
135