blob: a9e61ea54ca96ba69fa49f009d4fc98ff9cb1bdf [file] [log] [blame]
Ralf Baechle0004a9d2006-10-31 03:45:07 +00001/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (c) 2006 Ralf Baechle (ralf@linux-mips.org)
7 */
Jakub Jelinek4732efb2005-09-06 15:16:25 -07008#ifndef _ASM_FUTEX_H
9#define _ASM_FUTEX_H
10
11#ifdef __KERNEL__
12
13#include <linux/futex.h>
Jeff Dike730f4122008-04-30 00:54:49 -070014#include <linux/uaccess.h>
Markos Chandrasa6813fe2013-12-04 09:58:36 +000015#include <asm/asm-eva.h>
Ralf Baechle0004a9d2006-10-31 03:45:07 +000016#include <asm/barrier.h>
Maciej W. Rozyckib0984c42014-11-15 22:08:48 +000017#include <asm/compiler.h>
Jakub Jelinek4732efb2005-09-06 15:16:25 -070018#include <asm/errno.h>
Ralf Baechle6ee1da92006-05-03 20:42:39 +010019#include <asm/war.h>
Jakub Jelinek4732efb2005-09-06 15:16:25 -070020
Ralf Baechleebfaeba2005-09-15 08:52:34 +000021#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
22{ \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010023 if (cpu_has_llsc && R10000_LLSC_WAR) { \
24 __asm__ __volatile__( \
25 " .set push \n" \
26 " .set noat \n" \
Ralf Baechlea809d462014-03-30 13:20:10 +020027 " .set arch=r4000 \n" \
Atsushi Nemoto0307e8d2006-06-11 23:25:43 +090028 "1: ll %1, %4 # __futex_atomic_op \n" \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010029 " .set mips0 \n" \
30 " " insn " \n" \
Ralf Baechlea809d462014-03-30 13:20:10 +020031 " .set arch=r4000 \n" \
Atsushi Nemoto0307e8d2006-06-11 23:25:43 +090032 "2: sc $1, %2 \n" \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010033 " beqzl $1, 1b \n" \
Ralf Baechle17099b12007-07-14 13:24:05 +010034 __WEAK_LLSC_MB \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010035 "3: \n" \
Maciej W. Rozycki0e525e42014-11-15 22:09:31 +000036 " .insn \n" \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010037 " .set pop \n" \
38 " .set mips0 \n" \
39 " .section .fixup,\"ax\" \n" \
Atsushi Nemoto0307e8d2006-06-11 23:25:43 +090040 "4: li %0, %6 \n" \
Ralf Baechle0f67e902007-11-20 10:44:18 +000041 " j 3b \n" \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010042 " .previous \n" \
43 " .section __ex_table,\"a\" \n" \
44 " "__UA_ADDR "\t1b, 4b \n" \
45 " "__UA_ADDR "\t2b, 4b \n" \
46 " .previous \n" \
Maciej W. Rozyckib0984c42014-11-15 22:08:48 +000047 : "=r" (ret), "=&r" (oldval), \
Markos Chandras94bfb752015-01-26 12:44:11 +000048 "=" GCC_OFF_SMALL_ASM() (*uaddr) \
49 : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \
Maciej W. Rozyckib0984c42014-11-15 22:08:48 +000050 "i" (-EFAULT) \
Atsushi Nemoto0307e8d2006-06-11 23:25:43 +090051 : "memory"); \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010052 } else if (cpu_has_llsc) { \
53 __asm__ __volatile__( \
54 " .set push \n" \
55 " .set noat \n" \
Markos Chandras1922c352014-11-19 11:09:55 +000056 " .set "MIPS_ISA_ARCH_LEVEL" \n" \
Markos Chandrasa6813fe2013-12-04 09:58:36 +000057 "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010058 " .set mips0 \n" \
59 " " insn " \n" \
Markos Chandras1922c352014-11-19 11:09:55 +000060 " .set "MIPS_ISA_ARCH_LEVEL" \n" \
Markos Chandrasa6813fe2013-12-04 09:58:36 +000061 "2: "user_sc("$1", "%2")" \n" \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010062 " beqz $1, 1b \n" \
Ralf Baechle17099b12007-07-14 13:24:05 +010063 __WEAK_LLSC_MB \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010064 "3: \n" \
Maciej W. Rozycki0e525e42014-11-15 22:09:31 +000065 " .insn \n" \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010066 " .set pop \n" \
67 " .set mips0 \n" \
68 " .section .fixup,\"ax\" \n" \
Atsushi Nemoto0307e8d2006-06-11 23:25:43 +090069 "4: li %0, %6 \n" \
Ralf Baechle0f67e902007-11-20 10:44:18 +000070 " j 3b \n" \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010071 " .previous \n" \
72 " .section __ex_table,\"a\" \n" \
73 " "__UA_ADDR "\t1b, 4b \n" \
74 " "__UA_ADDR "\t2b, 4b \n" \
75 " .previous \n" \
Maciej W. Rozyckib0984c42014-11-15 22:08:48 +000076 : "=r" (ret), "=&r" (oldval), \
Markos Chandras94bfb752015-01-26 12:44:11 +000077 "=" GCC_OFF_SMALL_ASM() (*uaddr) \
78 : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \
Maciej W. Rozyckib0984c42014-11-15 22:08:48 +000079 "i" (-EFAULT) \
Atsushi Nemoto0307e8d2006-06-11 23:25:43 +090080 : "memory"); \
Ralf Baechle6ee1da92006-05-03 20:42:39 +010081 } else \
82 ret = -ENOSYS; \
Ralf Baechleebfaeba2005-09-15 08:52:34 +000083}
84
Jakub Jelinek4732efb2005-09-06 15:16:25 -070085static inline int
Jiri Slaby81da9f82017-08-24 09:31:05 +020086arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
Jakub Jelinek4732efb2005-09-06 15:16:25 -070087{
Jakub Jelinek4732efb2005-09-06 15:16:25 -070088 int oldval = 0, ret;
Jakub Jelinek4732efb2005-09-06 15:16:25 -070089
Peter Zijlstraa8663742006-12-06 20:32:20 -080090 pagefault_disable();
Jakub Jelinek4732efb2005-09-06 15:16:25 -070091
92 switch (op) {
93 case FUTEX_OP_SET:
Ralf Baechle70342282013-01-22 12:59:30 +010094 __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg);
Ralf Baechleebfaeba2005-09-15 08:52:34 +000095 break;
96
Jakub Jelinek4732efb2005-09-06 15:16:25 -070097 case FUTEX_OP_ADD:
Ralf Baechle70342282013-01-22 12:59:30 +010098 __futex_atomic_op("addu $1, %1, %z5",
99 ret, oldval, uaddr, oparg);
Ralf Baechleebfaeba2005-09-15 08:52:34 +0000100 break;
Jakub Jelinek4732efb2005-09-06 15:16:25 -0700101 case FUTEX_OP_OR:
Atsushi Nemoto0307e8d2006-06-11 23:25:43 +0900102 __futex_atomic_op("or $1, %1, %z5",
Ralf Baechle70342282013-01-22 12:59:30 +0100103 ret, oldval, uaddr, oparg);
Ralf Baechleebfaeba2005-09-15 08:52:34 +0000104 break;
Jakub Jelinek4732efb2005-09-06 15:16:25 -0700105 case FUTEX_OP_ANDN:
Atsushi Nemoto0307e8d2006-06-11 23:25:43 +0900106 __futex_atomic_op("and $1, %1, %z5",
Ralf Baechle70342282013-01-22 12:59:30 +0100107 ret, oldval, uaddr, ~oparg);
Ralf Baechleebfaeba2005-09-15 08:52:34 +0000108 break;
Jakub Jelinek4732efb2005-09-06 15:16:25 -0700109 case FUTEX_OP_XOR:
Atsushi Nemoto0307e8d2006-06-11 23:25:43 +0900110 __futex_atomic_op("xor $1, %1, %z5",
Ralf Baechle70342282013-01-22 12:59:30 +0100111 ret, oldval, uaddr, oparg);
Ralf Baechleebfaeba2005-09-15 08:52:34 +0000112 break;
Jakub Jelinek4732efb2005-09-06 15:16:25 -0700113 default:
114 ret = -ENOSYS;
115 }
116
Peter Zijlstraa8663742006-12-06 20:32:20 -0800117 pagefault_enable();
Jakub Jelinek4732efb2005-09-06 15:16:25 -0700118
Jiri Slaby81da9f82017-08-24 09:31:05 +0200119 if (!ret)
120 *oval = oldval;
121
Jakub Jelinek4732efb2005-09-06 15:16:25 -0700122 return ret;
123}
124
Ingo Molnare9056f12006-03-27 01:16:21 -0800125static inline int
Michel Lespinasse8d7718a2011-03-10 18:50:58 -0800126futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
127 u32 oldval, u32 newval)
Ingo Molnare9056f12006-03-27 01:16:21 -0800128{
Michel Lespinasse8d7718a2011-03-10 18:50:58 -0800129 int ret = 0;
130 u32 val;
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100131
Michel Lespinasse8d7718a2011-03-10 18:50:58 -0800132 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100133 return -EFAULT;
134
135 if (cpu_has_llsc && R10000_LLSC_WAR) {
136 __asm__ __volatile__(
137 "# futex_atomic_cmpxchg_inatomic \n"
138 " .set push \n"
139 " .set noat \n"
Ralf Baechlea809d462014-03-30 13:20:10 +0200140 " .set arch=r4000 \n"
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800141 "1: ll %1, %3 \n"
142 " bne %1, %z4, 3f \n"
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100143 " .set mips0 \n"
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800144 " move $1, %z5 \n"
Ralf Baechlea809d462014-03-30 13:20:10 +0200145 " .set arch=r4000 \n"
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800146 "2: sc $1, %2 \n"
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100147 " beqzl $1, 1b \n"
Ralf Baechle17099b12007-07-14 13:24:05 +0100148 __WEAK_LLSC_MB
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100149 "3: \n"
Maciej W. Rozycki0e525e42014-11-15 22:09:31 +0000150 " .insn \n"
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100151 " .set pop \n"
152 " .section .fixup,\"ax\" \n"
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800153 "4: li %0, %6 \n"
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100154 " j 3b \n"
155 " .previous \n"
156 " .section __ex_table,\"a\" \n"
157 " "__UA_ADDR "\t1b, 4b \n"
158 " "__UA_ADDR "\t2b, 4b \n"
159 " .previous \n"
Markos Chandras94bfb752015-01-26 12:44:11 +0000160 : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr)
161 : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
Maciej W. Rozyckib0984c42014-11-15 22:08:48 +0000162 "i" (-EFAULT)
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100163 : "memory");
164 } else if (cpu_has_llsc) {
165 __asm__ __volatile__(
166 "# futex_atomic_cmpxchg_inatomic \n"
167 " .set push \n"
168 " .set noat \n"
Markos Chandras1922c352014-11-19 11:09:55 +0000169 " .set "MIPS_ISA_ARCH_LEVEL" \n"
Markos Chandrasa6813fe2013-12-04 09:58:36 +0000170 "1: "user_ll("%1", "%3")" \n"
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800171 " bne %1, %z4, 3f \n"
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100172 " .set mips0 \n"
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800173 " move $1, %z5 \n"
Markos Chandras1922c352014-11-19 11:09:55 +0000174 " .set "MIPS_ISA_ARCH_LEVEL" \n"
Markos Chandrasa6813fe2013-12-04 09:58:36 +0000175 "2: "user_sc("$1", "%2")" \n"
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100176 " beqz $1, 1b \n"
Ralf Baechle17099b12007-07-14 13:24:05 +0100177 __WEAK_LLSC_MB
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100178 "3: \n"
Maciej W. Rozycki0e525e42014-11-15 22:09:31 +0000179 " .insn \n"
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100180 " .set pop \n"
181 " .section .fixup,\"ax\" \n"
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800182 "4: li %0, %6 \n"
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100183 " j 3b \n"
184 " .previous \n"
185 " .section __ex_table,\"a\" \n"
186 " "__UA_ADDR "\t1b, 4b \n"
187 " "__UA_ADDR "\t2b, 4b \n"
188 " .previous \n"
Markos Chandras94bfb752015-01-26 12:44:11 +0000189 : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr)
190 : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
Maciej W. Rozyckib0984c42014-11-15 22:08:48 +0000191 "i" (-EFAULT)
Ralf Baechle6ee1da92006-05-03 20:42:39 +0100192 : "memory");
193 } else
194 return -ENOSYS;
195
Michel Lespinasse37a9d912011-03-10 18:48:51 -0800196 *uval = val;
197 return ret;
Ingo Molnare9056f12006-03-27 01:16:21 -0800198}
199
Jakub Jelinek4732efb2005-09-06 15:16:25 -0700200#endif
Ralf Baechle0f67e902007-11-20 10:44:18 +0000201#endif /* _ASM_FUTEX_H */