| Ralf Baechle | 0004a9d | 2006-10-31 03:45:07 +0000 | [diff] [blame] | 1 | /* | 
 | 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 Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 8 | #ifndef _ASM_FUTEX_H | 
 | 9 | #define _ASM_FUTEX_H | 
 | 10 |  | 
 | 11 | #ifdef __KERNEL__ | 
 | 12 |  | 
 | 13 | #include <linux/futex.h> | 
| Jeff Dike | 730f412 | 2008-04-30 00:54:49 -0700 | [diff] [blame] | 14 | #include <linux/uaccess.h> | 
| Ralf Baechle | 0004a9d | 2006-10-31 03:45:07 +0000 | [diff] [blame] | 15 | #include <asm/barrier.h> | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 16 | #include <asm/errno.h> | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 17 | #include <asm/war.h> | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 18 |  | 
| Ralf Baechle | ebfaeba | 2005-09-15 08:52:34 +0000 | [diff] [blame] | 19 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)		\ | 
 | 20 | {									\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 21 | 	if (cpu_has_llsc && R10000_LLSC_WAR) {				\ | 
 | 22 | 		__asm__ __volatile__(					\ | 
 | 23 | 		"	.set	push				\n"	\ | 
 | 24 | 		"	.set	noat				\n"	\ | 
 | 25 | 		"	.set	mips3				\n"	\ | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 26 | 		"1:	ll	%1, %4	# __futex_atomic_op	\n"	\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 27 | 		"	.set	mips0				\n"	\ | 
 | 28 | 		"	" insn	"				\n"	\ | 
 | 29 | 		"	.set	mips3				\n"	\ | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 30 | 		"2:	sc	$1, %2				\n"	\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 31 | 		"	beqzl	$1, 1b				\n"	\ | 
| Ralf Baechle | 17099b1 | 2007-07-14 13:24:05 +0100 | [diff] [blame] | 32 | 		__WEAK_LLSC_MB						\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 33 | 		"3:						\n"	\ | 
 | 34 | 		"	.set	pop				\n"	\ | 
 | 35 | 		"	.set	mips0				\n"	\ | 
 | 36 | 		"	.section .fixup,\"ax\"			\n"	\ | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 37 | 		"4:	li	%0, %6				\n"	\ | 
| Ralf Baechle | 0f67e90 | 2007-11-20 10:44:18 +0000 | [diff] [blame] | 38 | 		"	j	3b				\n"	\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 39 | 		"	.previous				\n"	\ | 
 | 40 | 		"	.section __ex_table,\"a\"		\n"	\ | 
 | 41 | 		"	"__UA_ADDR "\t1b, 4b			\n"	\ | 
 | 42 | 		"	"__UA_ADDR "\t2b, 4b			\n"	\ | 
 | 43 | 		"	.previous				\n"	\ | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 44 | 		: "=r" (ret), "=&r" (oldval), "=R" (*uaddr)		\ | 
 | 45 | 		: "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT)	\ | 
 | 46 | 		: "memory");						\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 47 | 	} else if (cpu_has_llsc) {					\ | 
 | 48 | 		__asm__ __volatile__(					\ | 
 | 49 | 		"	.set	push				\n"	\ | 
 | 50 | 		"	.set	noat				\n"	\ | 
 | 51 | 		"	.set	mips3				\n"	\ | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 52 | 		"1:	ll	%1, %4	# __futex_atomic_op	\n"	\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 53 | 		"	.set	mips0				\n"	\ | 
 | 54 | 		"	" insn	"				\n"	\ | 
 | 55 | 		"	.set	mips3				\n"	\ | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 56 | 		"2:	sc	$1, %2				\n"	\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 57 | 		"	beqz	$1, 1b				\n"	\ | 
| Ralf Baechle | 17099b1 | 2007-07-14 13:24:05 +0100 | [diff] [blame] | 58 | 		__WEAK_LLSC_MB						\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 59 | 		"3:						\n"	\ | 
 | 60 | 		"	.set	pop				\n"	\ | 
 | 61 | 		"	.set	mips0				\n"	\ | 
 | 62 | 		"	.section .fixup,\"ax\"			\n"	\ | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 63 | 		"4:	li	%0, %6				\n"	\ | 
| Ralf Baechle | 0f67e90 | 2007-11-20 10:44:18 +0000 | [diff] [blame] | 64 | 		"	j	3b				\n"	\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 65 | 		"	.previous				\n"	\ | 
 | 66 | 		"	.section __ex_table,\"a\"		\n"	\ | 
 | 67 | 		"	"__UA_ADDR "\t1b, 4b			\n"	\ | 
 | 68 | 		"	"__UA_ADDR "\t2b, 4b			\n"	\ | 
 | 69 | 		"	.previous				\n"	\ | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 70 | 		: "=r" (ret), "=&r" (oldval), "=R" (*uaddr)		\ | 
 | 71 | 		: "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT)	\ | 
 | 72 | 		: "memory");						\ | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 73 | 	} else								\ | 
 | 74 | 		ret = -ENOSYS;						\ | 
| Ralf Baechle | ebfaeba | 2005-09-15 08:52:34 +0000 | [diff] [blame] | 75 | } | 
 | 76 |  | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 77 | static inline int | 
| Ralf Baechle | 49a89ef | 2007-10-11 23:46:15 +0100 | [diff] [blame] | 78 | futex_atomic_op_inuser(int encoded_op, int __user *uaddr) | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 79 | { | 
 | 80 | 	int op = (encoded_op >> 28) & 7; | 
 | 81 | 	int cmp = (encoded_op >> 24) & 15; | 
 | 82 | 	int oparg = (encoded_op << 8) >> 20; | 
 | 83 | 	int cmparg = (encoded_op << 20) >> 20; | 
 | 84 | 	int oldval = 0, ret; | 
 | 85 | 	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | 
 | 86 | 		oparg = 1 << oparg; | 
 | 87 |  | 
 | 88 | 	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) | 
 | 89 | 		return -EFAULT; | 
 | 90 |  | 
| Peter Zijlstra | a866374 | 2006-12-06 20:32:20 -0800 | [diff] [blame] | 91 | 	pagefault_disable(); | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 92 |  | 
 | 93 | 	switch (op) { | 
 | 94 | 	case FUTEX_OP_SET: | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 95 | 		__futex_atomic_op("move	$1, %z5", ret, oldval, uaddr, oparg); | 
| Ralf Baechle | ebfaeba | 2005-09-15 08:52:34 +0000 | [diff] [blame] | 96 | 		break; | 
 | 97 |  | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 98 | 	case FUTEX_OP_ADD: | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 99 | 		__futex_atomic_op("addu	$1, %1, %z5", | 
| Ralf Baechle | ebfaeba | 2005-09-15 08:52:34 +0000 | [diff] [blame] | 100 | 		                  ret, oldval, uaddr, oparg); | 
 | 101 | 		break; | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 102 | 	case FUTEX_OP_OR: | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 103 | 		__futex_atomic_op("or	$1, %1, %z5", | 
| Ralf Baechle | ebfaeba | 2005-09-15 08:52:34 +0000 | [diff] [blame] | 104 | 		                  ret, oldval, uaddr, oparg); | 
 | 105 | 		break; | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 106 | 	case FUTEX_OP_ANDN: | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 107 | 		__futex_atomic_op("and	$1, %1, %z5", | 
| Ralf Baechle | ebfaeba | 2005-09-15 08:52:34 +0000 | [diff] [blame] | 108 | 		                  ret, oldval, uaddr, ~oparg); | 
 | 109 | 		break; | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 110 | 	case FUTEX_OP_XOR: | 
| Atsushi Nemoto | 0307e8d | 2006-06-11 23:25:43 +0900 | [diff] [blame] | 111 | 		__futex_atomic_op("xor	$1, %1, %z5", | 
| Ralf Baechle | ebfaeba | 2005-09-15 08:52:34 +0000 | [diff] [blame] | 112 | 		                  ret, oldval, uaddr, oparg); | 
 | 113 | 		break; | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 114 | 	default: | 
 | 115 | 		ret = -ENOSYS; | 
 | 116 | 	} | 
 | 117 |  | 
| Peter Zijlstra | a866374 | 2006-12-06 20:32:20 -0800 | [diff] [blame] | 118 | 	pagefault_enable(); | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 119 |  | 
 | 120 | 	if (!ret) { | 
 | 121 | 		switch (cmp) { | 
 | 122 | 		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | 
 | 123 | 		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | 
 | 124 | 		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | 
 | 125 | 		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | 
 | 126 | 		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | 
 | 127 | 		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | 
 | 128 | 		default: ret = -ENOSYS; | 
 | 129 | 		} | 
 | 130 | 	} | 
 | 131 | 	return ret; | 
 | 132 | } | 
 | 133 |  | 
| Ingo Molnar | e9056f1 | 2006-03-27 01:16:21 -0800 | [diff] [blame] | 134 | static inline int | 
| Ingo Molnar | 8f17d3a | 2006-03-27 01:16:27 -0800 | [diff] [blame] | 135 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | 
| Ingo Molnar | e9056f1 | 2006-03-27 01:16:21 -0800 | [diff] [blame] | 136 | { | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 137 | 	int retval; | 
 | 138 |  | 
 | 139 | 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) | 
 | 140 | 		return -EFAULT; | 
 | 141 |  | 
 | 142 | 	if (cpu_has_llsc && R10000_LLSC_WAR) { | 
 | 143 | 		__asm__ __volatile__( | 
 | 144 | 		"# futex_atomic_cmpxchg_inatomic			\n" | 
 | 145 | 		"	.set	push					\n" | 
 | 146 | 		"	.set	noat					\n" | 
 | 147 | 		"	.set	mips3					\n" | 
 | 148 | 		"1:	ll	%0, %2					\n" | 
 | 149 | 		"	bne	%0, %z3, 3f				\n" | 
 | 150 | 		"	.set	mips0					\n" | 
 | 151 | 		"	move	$1, %z4					\n" | 
 | 152 | 		"	.set	mips3					\n" | 
 | 153 | 		"2:	sc	$1, %1					\n" | 
 | 154 | 		"	beqzl	$1, 1b					\n" | 
| Ralf Baechle | 17099b1 | 2007-07-14 13:24:05 +0100 | [diff] [blame] | 155 | 		__WEAK_LLSC_MB | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 156 | 		"3:							\n" | 
 | 157 | 		"	.set	pop					\n" | 
 | 158 | 		"	.section .fixup,\"ax\"				\n" | 
 | 159 | 		"4:	li	%0, %5					\n" | 
 | 160 | 		"	j	3b					\n" | 
 | 161 | 		"	.previous					\n" | 
 | 162 | 		"	.section __ex_table,\"a\"			\n" | 
 | 163 | 		"	"__UA_ADDR "\t1b, 4b				\n" | 
 | 164 | 		"	"__UA_ADDR "\t2b, 4b				\n" | 
 | 165 | 		"	.previous					\n" | 
 | 166 | 		: "=&r" (retval), "=R" (*uaddr) | 
 | 167 | 		: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) | 
 | 168 | 		: "memory"); | 
 | 169 | 	} else if (cpu_has_llsc) { | 
 | 170 | 		__asm__ __volatile__( | 
 | 171 | 		"# futex_atomic_cmpxchg_inatomic			\n" | 
 | 172 | 		"	.set	push					\n" | 
 | 173 | 		"	.set	noat					\n" | 
 | 174 | 		"	.set	mips3					\n" | 
 | 175 | 		"1:	ll	%0, %2					\n" | 
 | 176 | 		"	bne	%0, %z3, 3f				\n" | 
 | 177 | 		"	.set	mips0					\n" | 
 | 178 | 		"	move	$1, %z4					\n" | 
 | 179 | 		"	.set	mips3					\n" | 
 | 180 | 		"2:	sc	$1, %1					\n" | 
 | 181 | 		"	beqz	$1, 1b					\n" | 
| Ralf Baechle | 17099b1 | 2007-07-14 13:24:05 +0100 | [diff] [blame] | 182 | 		__WEAK_LLSC_MB | 
| Ralf Baechle | 6ee1da9 | 2006-05-03 20:42:39 +0100 | [diff] [blame] | 183 | 		"3:							\n" | 
 | 184 | 		"	.set	pop					\n" | 
 | 185 | 		"	.section .fixup,\"ax\"				\n" | 
 | 186 | 		"4:	li	%0, %5					\n" | 
 | 187 | 		"	j	3b					\n" | 
 | 188 | 		"	.previous					\n" | 
 | 189 | 		"	.section __ex_table,\"a\"			\n" | 
 | 190 | 		"	"__UA_ADDR "\t1b, 4b				\n" | 
 | 191 | 		"	"__UA_ADDR "\t2b, 4b				\n" | 
 | 192 | 		"	.previous					\n" | 
 | 193 | 		: "=&r" (retval), "=R" (*uaddr) | 
 | 194 | 		: "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) | 
 | 195 | 		: "memory"); | 
 | 196 | 	} else | 
 | 197 | 		return -ENOSYS; | 
 | 198 |  | 
 | 199 | 	return retval; | 
| Ingo Molnar | e9056f1 | 2006-03-27 01:16:21 -0800 | [diff] [blame] | 200 | } | 
 | 201 |  | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 202 | #endif | 
| Ralf Baechle | 0f67e90 | 2007-11-20 10:44:18 +0000 | [diff] [blame] | 203 | #endif /* _ASM_FUTEX_H */ |