1 #ifndef _ASM_POWERPC_FUTEX_H 2 #define _ASM_POWERPC_FUTEX_H 3 4 #ifdef __KERNEL__ 5 6 #include <linux/futex.h> 7 #include <linux/uaccess.h> 8 #include <asm/errno.h> 9 #include <asm/synch.h> 10 #include <asm/asm-compat.h> 11 12 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ 13 __asm__ __volatile ( \ 14 LWSYNC_ON_SMP \ 15 "1: lwarx %0,0,%2\n" \ 16 insn \ 17 PPC405_ERR77(0, %2) \ 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" \ 27 PPC_LONG "1b,4b,2b,4b\n" \ 28 ".previous" \ 29 : "=&r" (oldval), "=&r" (ret) \ 30 : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \ 31 : "cr0", "memory") 32 33 static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) 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 46 pagefault_disable(); 47 48 switch (op) { 49 case FUTEX_OP_SET: 50 __futex_atomic_op("mr %1,%4\n", ret, oldval, uaddr, oparg); 51 break; 52 case FUTEX_OP_ADD: 53 __futex_atomic_op("add %1,%0,%4\n", ret, oldval, uaddr, oparg); 54 break; 55 case FUTEX_OP_OR: 56 __futex_atomic_op("or %1,%0,%4\n", ret, oldval, uaddr, oparg); 57 break; 58 case FUTEX_OP_ANDN: 59 __futex_atomic_op("andc %1,%0,%4\n", ret, oldval, uaddr, oparg); 60 break; 61 case FUTEX_OP_XOR: 62 __futex_atomic_op("xor %1,%0,%4\n", ret, oldval, uaddr, oparg); 63 break; 64 default: 65 ret = -ENOSYS; 66 } 67 68 pagefault_enable(); 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 84 static inline int 85 futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) 86 { 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; 114 } 115 116 #endif /* __KERNEL__ */ 117 #endif /* _ASM_POWERPC_FUTEX_H */ 118