| David Gibson | 2ff2ae7 | 2005-11-02 13:58:22 +1100 | [diff] [blame] | 1 | #ifndef _ASM_POWERPC_FUTEX_H | 
 | 2 | #define _ASM_POWERPC_FUTEX_H | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 3 |  | 
 | 4 | #ifdef __KERNEL__ | 
 | 5 |  | 
 | 6 | #include <linux/futex.h> | 
 | 7 | #include <asm/errno.h> | 
| Becky Bruce | feaf7cf | 2005-09-22 14:20:04 -0500 | [diff] [blame] | 8 | #include <asm/synch.h> | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 9 | #include <asm/uaccess.h> | 
| David Gibson | 3ddfbcf | 2005-11-10 12:56:55 +1100 | [diff] [blame] | 10 | #include <asm/asm-compat.h> | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 11 |  | 
 | 12 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ | 
| David Gibson | 2ff2ae7 | 2005-11-02 13:58:22 +1100 | [diff] [blame] | 13 |   __asm__ __volatile ( \ | 
| Anton Blanchard | 144b9c1 | 2006-01-13 15:37:17 +1100 | [diff] [blame] | 14 | 	LWSYNC_ON_SMP \ | 
| David Gibson | 2ff2ae7 | 2005-11-02 13:58:22 +1100 | [diff] [blame] | 15 | "1:	lwarx	%0,0,%2\n" \ | 
 | 16 | 	insn \ | 
| David Gibson | 3ddfbcf | 2005-11-10 12:56:55 +1100 | [diff] [blame] | 17 | 	PPC405_ERR77(0, %2) \ | 
| David Gibson | 2ff2ae7 | 2005-11-02 13:58:22 +1100 | [diff] [blame] | 18 | "2:	stwcx.	%1,0,%2\n" \ | 
 | 19 | 	"bne-	1b\n" \ | 
 | 20 | 	"li	%1,0\n" \ | 
 | 21 | "3:	.section .fixup,\"ax\"\n" \ | 
 | 22 | "4:	li	%1,%3\n" \ | 
 | 23 | 	"b	3b\n" \ | 
 | 24 | 	".previous\n" \ | 
 | 25 | 	".section __ex_table,\"a\"\n" \ | 
 | 26 | 	".align 3\n" \ | 
| David Gibson | 3ddfbcf | 2005-11-10 12:56:55 +1100 | [diff] [blame] | 27 | 	PPC_LONG "1b,4b,2b,4b\n" \ | 
| David Gibson | 2ff2ae7 | 2005-11-02 13:58:22 +1100 | [diff] [blame] | 28 | 	".previous" \ | 
 | 29 | 	: "=&r" (oldval), "=&r" (ret) \ | 
 | 30 | 	: "b" (uaddr), "i" (-EFAULT), "1" (oparg) \ | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 31 | 	: "cr0", "memory") | 
 | 32 |  | 
| David Gibson | 2ff2ae7 | 2005-11-02 13:58:22 +1100 | [diff] [blame] | 33 | static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 34 | { | 
 | 35 | 	int op = (encoded_op >> 28) & 7; | 
 | 36 | 	int cmp = (encoded_op >> 24) & 15; | 
 | 37 | 	int oparg = (encoded_op << 8) >> 20; | 
 | 38 | 	int cmparg = (encoded_op << 20) >> 20; | 
 | 39 | 	int oldval = 0, ret; | 
 | 40 | 	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | 
 | 41 | 		oparg = 1 << oparg; | 
 | 42 |  | 
 | 43 | 	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) | 
 | 44 | 		return -EFAULT; | 
 | 45 |  | 
| Peter Zijlstra | a866374 | 2006-12-06 20:32:20 -0800 | [diff] [blame] | 46 | 	pagefault_disable(); | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 47 |  | 
 | 48 | 	switch (op) { | 
 | 49 | 	case FUTEX_OP_SET: | 
 | 50 | 		__futex_atomic_op("", ret, oldval, uaddr, oparg); | 
 | 51 | 		break; | 
 | 52 | 	case FUTEX_OP_ADD: | 
 | 53 | 		__futex_atomic_op("add %1,%0,%1\n", ret, oldval, uaddr, oparg); | 
 | 54 | 		break; | 
 | 55 | 	case FUTEX_OP_OR: | 
 | 56 | 		__futex_atomic_op("or %1,%0,%1\n", ret, oldval, uaddr, oparg); | 
 | 57 | 		break; | 
 | 58 | 	case FUTEX_OP_ANDN: | 
 | 59 | 		__futex_atomic_op("andc %1,%0,%1\n", ret, oldval, uaddr, oparg); | 
 | 60 | 		break; | 
 | 61 | 	case FUTEX_OP_XOR: | 
 | 62 | 		__futex_atomic_op("xor %1,%0,%1\n", ret, oldval, uaddr, oparg); | 
 | 63 | 		break; | 
 | 64 | 	default: | 
 | 65 | 		ret = -ENOSYS; | 
 | 66 | 	} | 
 | 67 |  | 
| Peter Zijlstra | a866374 | 2006-12-06 20:32:20 -0800 | [diff] [blame] | 68 | 	pagefault_enable(); | 
| Jakub Jelinek | 4732efb | 2005-09-06 15:16:25 -0700 | [diff] [blame] | 69 |  | 
 | 70 | 	if (!ret) { | 
 | 71 | 		switch (cmp) { | 
 | 72 | 		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | 
 | 73 | 		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | 
 | 74 | 		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | 
 | 75 | 		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | 
 | 76 | 		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | 
 | 77 | 		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | 
 | 78 | 		default: ret = -ENOSYS; | 
 | 79 | 		} | 
 | 80 | 	} | 
 | 81 | 	return ret; | 
 | 82 | } | 
 | 83 |  | 
| Ingo Molnar | e9056f1 | 2006-03-27 01:16:21 -0800 | [diff] [blame] | 84 | static inline int | 
| Ingo Molnar | 8f17d3a | 2006-03-27 01:16:27 -0800 | [diff] [blame] | 85 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | 
| Ingo Molnar | e9056f1 | 2006-03-27 01:16:21 -0800 | [diff] [blame] | 86 | { | 
| David Woodhouse | 6958829 | 2006-09-04 21:53:14 -0700 | [diff] [blame] | 87 | 	int prev; | 
 | 88 |  | 
 | 89 | 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) | 
 | 90 | 		return -EFAULT; | 
 | 91 |  | 
 | 92 |         __asm__ __volatile__ ( | 
 | 93 |         LWSYNC_ON_SMP | 
 | 94 | "1:     lwarx   %0,0,%2         # futex_atomic_cmpxchg_inatomic\n\ | 
 | 95 |         cmpw    0,%0,%3\n\ | 
 | 96 |         bne-    3f\n" | 
 | 97 |         PPC405_ERR77(0,%2) | 
 | 98 | "2:     stwcx.  %4,0,%2\n\ | 
 | 99 |         bne-    1b\n" | 
 | 100 |         ISYNC_ON_SMP | 
 | 101 | "3:	.section .fixup,\"ax\"\n\ | 
 | 102 | 4:	li	%0,%5\n\ | 
 | 103 | 	b	3b\n\ | 
 | 104 | 	.previous\n\ | 
 | 105 | 	.section __ex_table,\"a\"\n\ | 
 | 106 | 	.align 3\n\ | 
 | 107 | 	" PPC_LONG "1b,4b,2b,4b\n\ | 
 | 108 | 	.previous" \ | 
 | 109 |         : "=&r" (prev), "+m" (*uaddr) | 
 | 110 |         : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT) | 
 | 111 |         : "cc", "memory"); | 
 | 112 |  | 
 | 113 |         return prev; | 
| Ingo Molnar | e9056f1 | 2006-03-27 01:16:21 -0800 | [diff] [blame] | 114 | } | 
 | 115 |  | 
| David Gibson | 2ff2ae7 | 2005-11-02 13:58:22 +1100 | [diff] [blame] | 116 | #endif /* __KERNEL__ */ | 
 | 117 | #endif /* _ASM_POWERPC_FUTEX_H */ |