blob: 899e9f1d19e486defa413d087f6518ef38d35e29 [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 Deacon0ea366f2015-05-29 13:31:10 +010036 " prfm pstl1strm, %2\n"
Will Deacon8e86f0b2014-02-04 12:29:12 +000037 "1: ldxrb %w0, %2\n"
Will Deacon3a0310e2013-02-04 12:12:33 +000038 " stlxrb %w1, %w3, %2\n"
Catalin Marinas10b663a2012-03-05 11:49:34 +000039 " cbnz %w1, 1b\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010040 " dmb ish",
41 /* LSE atomics */
42 " nop\n"
Will Deacon0ea366f2015-05-29 13:31:10 +010043 " nop\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010044 " swpalb %w3, %w0, %2\n"
45 " nop\n"
46 " nop")
Will Deacon3a0310e2013-02-04 12:12:33 +000047 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr)
48 : "r" (x)
Will Deacon95c41892014-02-04 12:29:13 +000049 : "memory");
Catalin Marinas10b663a2012-03-05 11:49:34 +000050 break;
51 case 2:
Will Deaconc8366ba02015-03-31 14:11:24 +010052 asm volatile(ARM64_LSE_ATOMIC_INSN(
53 /* LL/SC */
Will Deacon0ea366f2015-05-29 13:31:10 +010054 " prfm pstl1strm, %2\n"
Will Deacon8e86f0b2014-02-04 12:29:12 +000055 "1: ldxrh %w0, %2\n"
Will Deacon3a0310e2013-02-04 12:12:33 +000056 " stlxrh %w1, %w3, %2\n"
Catalin Marinas10b663a2012-03-05 11:49:34 +000057 " cbnz %w1, 1b\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010058 " dmb ish",
59 /* LSE atomics */
60 " nop\n"
Will Deacon0ea366f2015-05-29 13:31:10 +010061 " nop\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010062 " swpalh %w3, %w0, %2\n"
63 " nop\n"
64 " nop")
Will Deacon3a0310e2013-02-04 12:12:33 +000065 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u16 *)ptr)
66 : "r" (x)
Will Deacon95c41892014-02-04 12:29:13 +000067 : "memory");
Catalin Marinas10b663a2012-03-05 11:49:34 +000068 break;
69 case 4:
Will Deaconc8366ba02015-03-31 14:11:24 +010070 asm volatile(ARM64_LSE_ATOMIC_INSN(
71 /* LL/SC */
Will Deacon0ea366f2015-05-29 13:31:10 +010072 " prfm pstl1strm, %2\n"
Will Deacon8e86f0b2014-02-04 12:29:12 +000073 "1: ldxr %w0, %2\n"
Will Deacon3a0310e2013-02-04 12:12:33 +000074 " stlxr %w1, %w3, %2\n"
Catalin Marinas10b663a2012-03-05 11:49:34 +000075 " cbnz %w1, 1b\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010076 " dmb ish",
77 /* LSE atomics */
78 " nop\n"
Will Deacon0ea366f2015-05-29 13:31:10 +010079 " nop\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010080 " swpal %w3, %w0, %2\n"
81 " nop\n"
82 " nop")
Will Deacon3a0310e2013-02-04 12:12:33 +000083 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u32 *)ptr)
84 : "r" (x)
Will Deacon95c41892014-02-04 12:29:13 +000085 : "memory");
Catalin Marinas10b663a2012-03-05 11:49:34 +000086 break;
87 case 8:
Will Deaconc8366ba02015-03-31 14:11:24 +010088 asm volatile(ARM64_LSE_ATOMIC_INSN(
89 /* LL/SC */
Will Deacon0ea366f2015-05-29 13:31:10 +010090 " prfm pstl1strm, %2\n"
Will Deacon8e86f0b2014-02-04 12:29:12 +000091 "1: ldxr %0, %2\n"
Will Deacon3a0310e2013-02-04 12:12:33 +000092 " stlxr %w1, %3, %2\n"
Catalin Marinas10b663a2012-03-05 11:49:34 +000093 " cbnz %w1, 1b\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010094 " dmb ish",
95 /* LSE atomics */
96 " nop\n"
Will Deacon0ea366f2015-05-29 13:31:10 +010097 " nop\n"
Will Deaconc8366ba02015-03-31 14:11:24 +010098 " swpal %3, %0, %2\n"
99 " nop\n"
100 " nop")
Will Deacon3a0310e2013-02-04 12:12:33 +0000101 : "=&r" (ret), "=&r" (tmp), "+Q" (*(u64 *)ptr)
102 : "r" (x)
Will Deacon95c41892014-02-04 12:29:13 +0000103 : "memory");
Catalin Marinas10b663a2012-03-05 11:49:34 +0000104 break;
105 default:
106 BUILD_BUG();
107 }
108
109 return ret;
110}
111
112#define xchg(ptr,x) \
Will Deacone1dfda92014-04-30 16:23:06 +0100113({ \
114 __typeof__(*(ptr)) __ret; \
115 __ret = (__typeof__(*(ptr))) \
116 __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))); \
117 __ret; \
118})
Catalin Marinas10b663a2012-03-05 11:49:34 +0000119
120static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
121 unsigned long new, int size)
122{
Catalin Marinas10b663a2012-03-05 11:49:34 +0000123 switch (size) {
124 case 1:
Will Deacona14949e2015-07-30 19:19:43 +0100125 return __cmpxchg_case_1(ptr, (u8)old, new);
Catalin Marinas10b663a2012-03-05 11:49:34 +0000126 case 2:
Will Deacona14949e2015-07-30 19:19:43 +0100127 return __cmpxchg_case_2(ptr, (u16)old, new);
Catalin Marinas10b663a2012-03-05 11:49:34 +0000128 case 4:
Will Deaconc342f782015-04-23 20:08:49 +0100129 return __cmpxchg_case_4(ptr, old, new);
Catalin Marinas10b663a2012-03-05 11:49:34 +0000130 case 8:
Will Deaconc342f782015-04-23 20:08:49 +0100131 return __cmpxchg_case_8(ptr, old, new);
Catalin Marinas10b663a2012-03-05 11:49:34 +0000132 default:
133 BUILD_BUG();
134 }
135
Will Deaconc342f782015-04-23 20:08:49 +0100136 unreachable();
Catalin Marinas10b663a2012-03-05 11:49:34 +0000137}
138
139static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
140 unsigned long new, int size)
141{
Will Deaconc342f782015-04-23 20:08:49 +0100142 switch (size) {
143 case 1:
Will Deacona14949e2015-07-30 19:19:43 +0100144 return __cmpxchg_case_mb_1(ptr, (u8)old, new);
Will Deaconc342f782015-04-23 20:08:49 +0100145 case 2:
Will Deacona14949e2015-07-30 19:19:43 +0100146 return __cmpxchg_case_mb_2(ptr, (u16)old, new);
Will Deaconc342f782015-04-23 20:08:49 +0100147 case 4:
148 return __cmpxchg_case_mb_4(ptr, old, new);
149 case 8:
150 return __cmpxchg_case_mb_8(ptr, old, new);
151 default:
152 BUILD_BUG();
153 }
Catalin Marinas10b663a2012-03-05 11:49:34 +0000154
Will Deaconc342f782015-04-23 20:08:49 +0100155 unreachable();
Catalin Marinas10b663a2012-03-05 11:49:34 +0000156}
157
Mark Hambleton60010e52013-12-03 19:19:12 +0000158#define cmpxchg(ptr, o, n) \
159({ \
160 __typeof__(*(ptr)) __ret; \
161 __ret = (__typeof__(*(ptr))) \
162 __cmpxchg_mb((ptr), (unsigned long)(o), (unsigned long)(n), \
163 sizeof(*(ptr))); \
164 __ret; \
165})
Catalin Marinas10b663a2012-03-05 11:49:34 +0000166
Mark Hambleton60010e52013-12-03 19:19:12 +0000167#define cmpxchg_local(ptr, o, n) \
168({ \
169 __typeof__(*(ptr)) __ret; \
170 __ret = (__typeof__(*(ptr))) \
171 __cmpxchg((ptr), (unsigned long)(o), \
172 (unsigned long)(n), sizeof(*(ptr))); \
173 __ret; \
174})
Catalin Marinas10b663a2012-03-05 11:49:34 +0000175
Will Deacone9a4b792015-05-14 18:05:50 +0100176#define system_has_cmpxchg_double() 1
177
178#define __cmpxchg_double_check(ptr1, ptr2) \
179({ \
180 if (sizeof(*(ptr1)) != 8) \
181 BUILD_BUG(); \
182 VM_BUG_ON((unsigned long *)(ptr2) - (unsigned long *)(ptr1) != 1); \
183})
184
Steve Capper5284e1b2014-10-24 13:22:20 +0100185#define cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \
186({\
187 int __ret;\
Will Deacone9a4b792015-05-14 18:05:50 +0100188 __cmpxchg_double_check(ptr1, ptr2); \
189 __ret = !__cmpxchg_double_mb((unsigned long)(o1), (unsigned long)(o2), \
190 (unsigned long)(n1), (unsigned long)(n2), \
191 ptr1); \
Steve Capper5284e1b2014-10-24 13:22:20 +0100192 __ret; \
193})
194
195#define cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \
196({\
197 int __ret;\
Will Deacone9a4b792015-05-14 18:05:50 +0100198 __cmpxchg_double_check(ptr1, ptr2); \
199 __ret = !__cmpxchg_double((unsigned long)(o1), (unsigned long)(o2), \
200 (unsigned long)(n1), (unsigned long)(n2), \
201 ptr1); \
Steve Capper5284e1b2014-10-24 13:22:20 +0100202 __ret; \
203})
204
Steve Capperf3eab712015-03-22 14:51:51 +0000205#define _protect_cmpxchg_local(pcp, o, n) \
206({ \
207 typeof(*raw_cpu_ptr(&(pcp))) __ret; \
208 preempt_disable(); \
209 __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n); \
210 preempt_enable(); \
211 __ret; \
212})
Steve Capper5284e1b2014-10-24 13:22:20 +0100213
Steve Capperf3eab712015-03-22 14:51:51 +0000214#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
215#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
216#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
217#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
218
219#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
220({ \
221 int __ret; \
222 preempt_disable(); \
223 __ret = cmpxchg_double_local( raw_cpu_ptr(&(ptr1)), \
224 raw_cpu_ptr(&(ptr2)), \
225 o1, o2, n1, n2); \
226 preempt_enable(); \
227 __ret; \
228})
Steve Capper5284e1b2014-10-24 13:22:20 +0100229
Chen Ganga84b0862013-04-22 06:08:41 +0100230#define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n))
231#define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n))
232
Will Deaconcf10b792013-10-09 15:54:28 +0100233#define cmpxchg64_relaxed(ptr,o,n) cmpxchg_local((ptr),(o),(n))
234
Catalin Marinas10b663a2012-03-05 11:49:34 +0000235#endif /* __ASM_CMPXCHG_H */