| David S. Miller | 043df59 | 2006-02-25 12:15:31 -0800 | [diff] [blame] | 1 | #ifndef _SPARC64_FUTEX_H | 
|  | 2 | #define _SPARC64_FUTEX_H | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 3 |  | 
| David S. Miller | 043df59 | 2006-02-25 12:15:31 -0800 | [diff] [blame] | 4 | #include <linux/futex.h> | 
|  | 5 | #include <asm/errno.h> | 
|  | 6 | #include <asm/system.h> | 
|  | 7 | #include <asm/uaccess.h> | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 8 |  | 
| David S. Miller | 043df59 | 2006-02-25 12:15:31 -0800 | [diff] [blame] | 9 | #define __futex_cas_op(insn, ret, oldval, uaddr, oparg)	\ | 
|  | 10 | __asm__ __volatile__(				\ | 
|  | 11 | "\n1:	lduwa	[%3] %%asi, %2\n"		\ | 
|  | 12 | "	" insn "\n"				\ | 
|  | 13 | "2:	casa	[%3] %%asi, %2, %1\n"		\ | 
|  | 14 | "	cmp	%2, %1\n"			\ | 
|  | 15 | "	bne,pn	%%icc, 1b\n"			\ | 
|  | 16 | "	 mov	0, %0\n"			\ | 
|  | 17 | "3:\n"						\ | 
|  | 18 | "	.section .fixup,#alloc,#execinstr\n"	\ | 
|  | 19 | "	.align	4\n"				\ | 
|  | 20 | "4:	ba	3b\n"				\ | 
|  | 21 | "	 mov	%5, %0\n"			\ | 
|  | 22 | "	.previous\n"				\ | 
| David S. Miller | 4d000d5 | 2006-03-04 23:23:56 -0800 | [diff] [blame] | 23 | "	.section __ex_table,\"a\"\n"		\ | 
| David S. Miller | 043df59 | 2006-02-25 12:15:31 -0800 | [diff] [blame] | 24 | "	.align	4\n"				\ | 
|  | 25 | "	.word	1b, 4b\n"			\ | 
|  | 26 | "	.word	2b, 4b\n"			\ | 
|  | 27 | "	.previous\n"				\ | 
|  | 28 | : "=&r" (ret), "=&r" (oldval), "=&r" (tem)	\ | 
|  | 29 | : "r" (uaddr), "r" (oparg), "i" (-EFAULT)	\ | 
|  | 30 | : "memory") | 
|  | 31 |  | 
|  | 32 | static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr) | 
|  | 33 | { | 
|  | 34 | int op = (encoded_op >> 28) & 7; | 
|  | 35 | int cmp = (encoded_op >> 24) & 15; | 
|  | 36 | int oparg = (encoded_op << 8) >> 20; | 
|  | 37 | int cmparg = (encoded_op << 20) >> 20; | 
|  | 38 | int oldval = 0, ret, tem; | 
|  | 39 |  | 
|  | 40 | if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))) | 
|  | 41 | return -EFAULT; | 
|  | 42 | if (unlikely((((unsigned long) uaddr) & 0x3UL))) | 
|  | 43 | return -EINVAL; | 
|  | 44 |  | 
|  | 45 | if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | 
|  | 46 | oparg = 1 << oparg; | 
|  | 47 |  | 
| Peter Zijlstra | a866374 | 2006-12-06 20:32:20 -0800 | [diff] [blame] | 48 | pagefault_disable(); | 
| David S. Miller | 043df59 | 2006-02-25 12:15:31 -0800 | [diff] [blame] | 49 |  | 
|  | 50 | switch (op) { | 
|  | 51 | case FUTEX_OP_SET: | 
|  | 52 | __futex_cas_op("mov\t%4, %1", ret, oldval, uaddr, oparg); | 
|  | 53 | break; | 
|  | 54 | case FUTEX_OP_ADD: | 
|  | 55 | __futex_cas_op("add\t%2, %4, %1", ret, oldval, uaddr, oparg); | 
|  | 56 | break; | 
|  | 57 | case FUTEX_OP_OR: | 
|  | 58 | __futex_cas_op("or\t%2, %4, %1", ret, oldval, uaddr, oparg); | 
|  | 59 | break; | 
|  | 60 | case FUTEX_OP_ANDN: | 
|  | 61 | __futex_cas_op("and\t%2, %4, %1", ret, oldval, uaddr, oparg); | 
|  | 62 | break; | 
|  | 63 | case FUTEX_OP_XOR: | 
|  | 64 | __futex_cas_op("xor\t%2, %4, %1", ret, oldval, uaddr, oparg); | 
|  | 65 | break; | 
|  | 66 | default: | 
|  | 67 | ret = -ENOSYS; | 
|  | 68 | } | 
|  | 69 |  | 
| Peter Zijlstra | a866374 | 2006-12-06 20:32:20 -0800 | [diff] [blame] | 70 | pagefault_enable(); | 
| David S. Miller | 043df59 | 2006-02-25 12:15:31 -0800 | [diff] [blame] | 71 |  | 
|  | 72 | if (!ret) { | 
|  | 73 | switch (cmp) { | 
|  | 74 | case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | 
|  | 75 | case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | 
|  | 76 | case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | 
|  | 77 | case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | 
|  | 78 | case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | 
|  | 79 | case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | 
|  | 80 | default: ret = -ENOSYS; | 
|  | 81 | } | 
|  | 82 | } | 
|  | 83 | return ret; | 
|  | 84 | } | 
|  | 85 |  | 
| Ingo Molnar | e9056f1 | 2006-03-27 01:16:21 -0800 | [diff] [blame] | 86 | static inline int | 
| David S. Miller | 6e57a3a8 | 2006-03-28 01:00:08 -0800 | [diff] [blame] | 87 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | 
| Ingo Molnar | e9056f1 | 2006-03-27 01:16:21 -0800 | [diff] [blame] | 88 | { | 
| David S. Miller | 6e57a3a8 | 2006-03-28 01:00:08 -0800 | [diff] [blame] | 89 | __asm__ __volatile__( | 
| David S. Miller | c7fed9d | 2006-11-01 16:30:39 -0800 | [diff] [blame] | 90 | "\n1:	casa	[%3] %%asi, %2, %0\n" | 
|  | 91 | "2:\n" | 
| David S. Miller | 6e57a3a8 | 2006-03-28 01:00:08 -0800 | [diff] [blame] | 92 | "	.section .fixup,#alloc,#execinstr\n" | 
|  | 93 | "	.align	4\n" | 
| David S. Miller | c7fed9d | 2006-11-01 16:30:39 -0800 | [diff] [blame] | 94 | "3:	ba	2b\n" | 
|  | 95 | "	 mov	%4, %0\n" | 
| David S. Miller | 6e57a3a8 | 2006-03-28 01:00:08 -0800 | [diff] [blame] | 96 | "	.previous\n" | 
|  | 97 | "	.section __ex_table,\"a\"\n" | 
|  | 98 | "	.align	4\n" | 
| David S. Miller | c7fed9d | 2006-11-01 16:30:39 -0800 | [diff] [blame] | 99 | "	.word	1b, 3b\n" | 
| David S. Miller | 6e57a3a8 | 2006-03-28 01:00:08 -0800 | [diff] [blame] | 100 | "	.previous\n" | 
| David S. Miller | c7fed9d | 2006-11-01 16:30:39 -0800 | [diff] [blame] | 101 | : "=r" (newval) | 
|  | 102 | : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT) | 
| David S. Miller | 6e57a3a8 | 2006-03-28 01:00:08 -0800 | [diff] [blame] | 103 | : "memory"); | 
|  | 104 |  | 
| David S. Miller | c7fed9d | 2006-11-01 16:30:39 -0800 | [diff] [blame] | 105 | return newval; | 
| Ingo Molnar | e9056f1 | 2006-03-27 01:16:21 -0800 | [diff] [blame] | 106 | } | 
|  | 107 |  | 
| David S. Miller | 043df59 | 2006-02-25 12:15:31 -0800 | [diff] [blame] | 108 | #endif /* !(_SPARC64_FUTEX_H) */ |