blob: f70212629d02f99958ad00d9d150045b474370bf [file] [log] [blame]
Catalin Marinas10b663a2012-03-05 11:49:34 +00001/*
2 * Based on arch/arm/include/asm/cmpxchg.h
3 *
4 * Copyright (C) 2012 ARM Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18#ifndef __ASM_CMPXCHG_H
19#define __ASM_CMPXCHG_H
20
21#include <linux/bug.h>
Steve Capper5284e1b2014-10-24 13:22:20 +010022#include <linux/mmdebug.h>
Catalin Marinas10b663a2012-03-05 11:49:34 +000023
Will Deaconc342f782015-04-23 20:08:49 +010024#include <asm/atomic.h>
Catalin Marinas10b663a2012-03-05 11:49:34 +000025#include <asm/barrier.h>
Will Deaconc8366ba02015-03-31 14:11:24 +010026#include <asm/lse.h>
Catalin Marinas10b663a2012-03-05 11:49:34 +000027
28static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
29{
30 unsigned long ret, tmp;
31
32 switch (size) {
33 case 1:
Will Deaconc8366ba02015-03-31 14:11:24 +010034 asm volatile(ARM64_LSE_ATOMIC_INSN(
35 /* LL/SC */
Will Deacon8e86f0b2014-02-04 12:29:12 +000036 "1: ldxrb %w0, %2\n"
Will Deacon3a0310e2013-02-04 12:12:33 +000037 " stlxrb %w1, %w3, %2\n"
Catalin Marinas10b663a2012-03-05 11:49:34 +000038 " cbnz %w1, 1b\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010039 " dmb ish",
40 /* LSE atomics */
41 " nop\n"
42 " swpalb %w3, %w0, %2\n"
43 " nop\n"
44 " nop")
Will Deacon3a0310e2013-02-04 12:12:33 +000045 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr)
46 : "r" (x)
Will Deacon95c41892014-02-04 12:29:13 +000047 : "memory");
Catalin Marinas10b663a2012-03-05 11:49:34 +000048 break;
49 case 2:
Will Deaconc8366ba02015-03-31 14:11:24 +010050 asm volatile(ARM64_LSE_ATOMIC_INSN(
51 /* LL/SC */
Will Deacon8e86f0b2014-02-04 12:29:12 +000052 "1: ldxrh %w0, %2\n"
Will Deacon3a0310e2013-02-04 12:12:33 +000053 " stlxrh %w1, %w3, %2\n"
Catalin Marinas10b663a2012-03-05 11:49:34 +000054 " cbnz %w1, 1b\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010055 " dmb ish",
56 /* LSE atomics */
57 " nop\n"
58 " swpalh %w3, %w0, %2\n"
59 " nop\n"
60 " nop")
Will Deacon3a0310e2013-02-04 12:12:33 +000061 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u16 *)ptr)
62 : "r" (x)
Will Deacon95c41892014-02-04 12:29:13 +000063 : "memory");
Catalin Marinas10b663a2012-03-05 11:49:34 +000064 break;
65 case 4:
Will Deaconc8366ba02015-03-31 14:11:24 +010066 asm volatile(ARM64_LSE_ATOMIC_INSN(
67 /* LL/SC */
Will Deacon8e86f0b2014-02-04 12:29:12 +000068 "1: ldxr %w0, %2\n"
Will Deacon3a0310e2013-02-04 12:12:33 +000069 " stlxr %w1, %w3, %2\n"
Catalin Marinas10b663a2012-03-05 11:49:34 +000070 " cbnz %w1, 1b\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010071 " dmb ish",
72 /* LSE atomics */
73 " nop\n"
74 " swpal %w3, %w0, %2\n"
75 " nop\n"
76 " nop")
Will Deacon3a0310e2013-02-04 12:12:33 +000077 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u32 *)ptr)
78 : "r" (x)
Will Deacon95c41892014-02-04 12:29:13 +000079 : "memory");
Catalin Marinas10b663a2012-03-05 11:49:34 +000080 break;
81 case 8:
Will Deaconc8366ba02015-03-31 14:11:24 +010082 asm volatile(ARM64_LSE_ATOMIC_INSN(
83 /* LL/SC */
Will Deacon8e86f0b2014-02-04 12:29:12 +000084 "1: ldxr %0, %2\n"
Will Deacon3a0310e2013-02-04 12:12:33 +000085 " stlxr %w1, %3, %2\n"
Catalin Marinas10b663a2012-03-05 11:49:34 +000086 " cbnz %w1, 1b\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010087 " dmb ish",
88 /* LSE atomics */
89 " nop\n"
90 " swpal %3, %0, %2\n"
91 " nop\n"
92 " nop")
Will Deacon3a0310e2013-02-04 12:12:33 +000093 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u64 *)ptr)
94 : "r" (x)
Will Deacon95c41892014-02-04 12:29:13 +000095 : "memory");
Catalin Marinas10b663a2012-03-05 11:49:34 +000096 break;
97 default:
98 BUILD_BUG();
99 }
100
101 return ret;
102}
103
104#define xchg(ptr,x) \
Will Deacone1dfda92014-04-30 16:23:06 +0100105({ \
106 __typeof__(*(ptr)) __ret; \
107 __ret = (__typeof__(*(ptr))) \
108 __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))); \
109 __ret; \
110})
Catalin Marinas10b663a2012-03-05 11:49:34 +0000111
112static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
113 unsigned long new, int size)
114{
Catalin Marinas10b663a2012-03-05 11:49:34 +0000115 switch (size) {
116 case 1:
Will Deaconc342f782015-04-23 20:08:49 +0100117 return __cmpxchg_case_1(ptr, old, new);
Catalin Marinas10b663a2012-03-05 11:49:34 +0000118 case 2:
Will Deaconc342f782015-04-23 20:08:49 +0100119 return __cmpxchg_case_2(ptr, old, new);
Catalin Marinas10b663a2012-03-05 11:49:34 +0000120 case 4:
Will Deaconc342f782015-04-23 20:08:49 +0100121 return __cmpxchg_case_4(ptr, old, new);
Catalin Marinas10b663a2012-03-05 11:49:34 +0000122 case 8:
Will Deaconc342f782015-04-23 20:08:49 +0100123 return __cmpxchg_case_8(ptr, old, new);
Catalin Marinas10b663a2012-03-05 11:49:34 +0000124 default:
125 BUILD_BUG();
126 }
127
Will Deaconc342f782015-04-23 20:08:49 +0100128 unreachable();
Catalin Marinas10b663a2012-03-05 11:49:34 +0000129}
130
131static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
132 unsigned long new, int size)
133{
Will Deaconc342f782015-04-23 20:08:49 +0100134 switch (size) {
135 case 1:
136 return __cmpxchg_case_mb_1(ptr, old, new);
137 case 2:
138 return __cmpxchg_case_mb_2(ptr, old, new);
139 case 4:
140 return __cmpxchg_case_mb_4(ptr, old, new);
141 case 8:
142 return __cmpxchg_case_mb_8(ptr, old, new);
143 default:
144 BUILD_BUG();
145 }
Catalin Marinas10b663a2012-03-05 11:49:34 +0000146
Will Deaconc342f782015-04-23 20:08:49 +0100147 unreachable();
Catalin Marinas10b663a2012-03-05 11:49:34 +0000148}
149
Mark Hambleton60010e52013-12-03 19:19:12 +0000150#define cmpxchg(ptr, o, n) \
151({ \
152 __typeof__(*(ptr)) __ret; \
153 __ret = (__typeof__(*(ptr))) \
154 __cmpxchg_mb((ptr), (unsigned long)(o), (unsigned long)(n), \
155 sizeof(*(ptr))); \
156 __ret; \
157})
Catalin Marinas10b663a2012-03-05 11:49:34 +0000158
Mark Hambleton60010e52013-12-03 19:19:12 +0000159#define cmpxchg_local(ptr, o, n) \
160({ \
161 __typeof__(*(ptr)) __ret; \
162 __ret = (__typeof__(*(ptr))) \
163 __cmpxchg((ptr), (unsigned long)(o), \
164 (unsigned long)(n), sizeof(*(ptr))); \
165 __ret; \
166})
Catalin Marinas10b663a2012-03-05 11:49:34 +0000167
Will Deacone9a4b792015-05-14 18:05:50 +0100168#define system_has_cmpxchg_double() 1
169
170#define __cmpxchg_double_check(ptr1, ptr2) \
171({ \
172 if (sizeof(*(ptr1)) != 8) \
173 BUILD_BUG(); \
174 VM_BUG_ON((unsigned long *)(ptr2) - (unsigned long *)(ptr1) != 1); \
175})
176
Steve Capper5284e1b2014-10-24 13:22:20 +0100177#define cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \
178({\
179 int __ret;\
Will Deacone9a4b792015-05-14 18:05:50 +0100180 __cmpxchg_double_check(ptr1, ptr2); \
181 __ret = !__cmpxchg_double_mb((unsigned long)(o1), (unsigned long)(o2), \
182 (unsigned long)(n1), (unsigned long)(n2), \
183 ptr1); \
Steve Capper5284e1b2014-10-24 13:22:20 +0100184 __ret; \
185})
186
187#define cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \
188({\
189 int __ret;\
Will Deacone9a4b792015-05-14 18:05:50 +0100190 __cmpxchg_double_check(ptr1, ptr2); \
191 __ret = !__cmpxchg_double((unsigned long)(o1), (unsigned long)(o2), \
192 (unsigned long)(n1), (unsigned long)(n2), \
193 ptr1); \
Steve Capper5284e1b2014-10-24 13:22:20 +0100194 __ret; \
195})
196
Steve Capperf3eab712015-03-22 14:51:51 +0000197#define _protect_cmpxchg_local(pcp, o, n) \
198({ \
199 typeof(*raw_cpu_ptr(&(pcp))) __ret; \
200 preempt_disable(); \
201 __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n); \
202 preempt_enable(); \
203 __ret; \
204})
Steve Capper5284e1b2014-10-24 13:22:20 +0100205
Steve Capperf3eab712015-03-22 14:51:51 +0000206#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
207#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
208#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
209#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
210
211#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
212({ \
213 int __ret; \
214 preempt_disable(); \
215 __ret = cmpxchg_double_local( raw_cpu_ptr(&(ptr1)), \
216 raw_cpu_ptr(&(ptr2)), \
217 o1, o2, n1, n2); \
218 preempt_enable(); \
219 __ret; \
220})
Steve Capper5284e1b2014-10-24 13:22:20 +0100221
Chen Ganga84b0862013-04-22 06:08:41 +0100222#define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n))
223#define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n))
224
Will Deaconcf10b792013-10-09 15:54:28 +0100225#define cmpxchg64_relaxed(ptr,o,n) cmpxchg_local((ptr),(o),(n))
226
Catalin Marinas10b663a2012-03-05 11:49:34 +0000227#endif /* __ASM_CMPXCHG_H */