1 /* 2 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * Vineetg: August 2010: From Android kernel work 9 */ 10 11 #ifndef _ASM_FUTEX_H 12 #define _ASM_FUTEX_H 13 14 #include <linux/futex.h> 15 #include <linux/preempt.h> 16 #include <linux/uaccess.h> 17 #include <asm/errno.h> 18 19 #ifdef CONFIG_ARC_HAS_LLSC 20 21 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\ 22 \ 23 smp_mb(); \ 24 __asm__ __volatile__( \ 25 "1: llock %1, [%2] \n" \ 26 insn "\n" \ 27 "2: scond %0, [%2] \n" \ 28 " bnz 1b \n" \ 29 " mov %0, 0 \n" \ 30 "3: \n" \ 31 " .section .fixup,\"ax\" \n" \ 32 " .align 4 \n" \ 33 "4: mov %0, %4 \n" \ 34 " j 3b \n" \ 35 " .previous \n" \ 36 " .section __ex_table,\"a\" \n" \ 37 " .align 4 \n" \ 38 " .word 1b, 4b \n" \ 39 " .word 2b, 4b \n" \ 40 " .previous \n" \ 41 \ 42 : "=&r" (ret), "=&r" (oldval) \ 43 : "r" (uaddr), "r" (oparg), "ir" (-EFAULT) \ 44 : "cc", "memory"); \ 45 smp_mb() \ 46 47 #else /* !CONFIG_ARC_HAS_LLSC */ 48 49 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\ 50 \ 51 smp_mb(); \ 52 __asm__ __volatile__( \ 53 "1: ld %1, [%2] \n" \ 54 insn "\n" \ 55 "2: st %0, [%2] \n" \ 56 " mov %0, 0 \n" \ 57 "3: \n" \ 58 " .section .fixup,\"ax\" \n" \ 59 " .align 4 \n" \ 60 "4: mov %0, %4 \n" \ 61 " j 3b \n" \ 62 " .previous \n" \ 63 " .section __ex_table,\"a\" \n" \ 64 " .align 4 \n" \ 65 " .word 1b, 4b \n" \ 66 " .word 2b, 4b \n" \ 67 " .previous \n" \ 68 \ 69 : "=&r" (ret), "=&r" (oldval) \ 70 : "r" (uaddr), "r" (oparg), "ir" (-EFAULT) \ 71 : "cc", "memory"); \ 72 smp_mb() \ 73 74 #endif 75 76 static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, 77 u32 __user *uaddr) 78 { 79 int oldval = 0, ret; 80 81 #ifndef CONFIG_ARC_HAS_LLSC 82 preempt_disable(); /* to guarantee atomic r-m-w of futex op */ 83 #endif 84 pagefault_disable(); 85 86 switch (op) { 87 case FUTEX_OP_SET: 88 __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg); 89 break; 90 case FUTEX_OP_ADD: 91 /* oldval = *uaddr; *uaddr += oparg ; ret = *uaddr */ 92 __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg); 93 break; 94 case FUTEX_OP_OR: 95 __futex_atomic_op("or %0, %1, %3", ret, oldval, uaddr, oparg); 96 break; 97 case FUTEX_OP_ANDN: 98 __futex_atomic_op("bic %0, %1, %3", ret, oldval, uaddr, oparg); 99 break; 100 case FUTEX_OP_XOR: 101 __futex_atomic_op("xor %0, %1, %3", ret, oldval, uaddr, oparg); 102 break; 103 default: 104 ret = -ENOSYS; 105 } 106 107 pagefault_enable(); 108 #ifndef CONFIG_ARC_HAS_LLSC 109 preempt_enable(); 110 #endif 111 112 if (!ret) 113 *oval = oldval; 114 115 return ret; 116 } 117 118 /* 119 * cmpxchg of futex (pagefaults disabled by caller) 120 * Return 0 for success, -EFAULT otherwise 121 */ 122 static inline int 123 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 expval, 124 u32 newval) 125 { 126 int ret = 0; 127 u32 existval; 128 129 if (!access_ok(uaddr, sizeof(u32))) 130 return -EFAULT; 131 132 #ifndef CONFIG_ARC_HAS_LLSC 133 preempt_disable(); /* to guarantee atomic r-m-w of futex op */ 134 #endif 135 smp_mb(); 136 137 __asm__ __volatile__( 138 #ifdef CONFIG_ARC_HAS_LLSC 139 "1: llock %1, [%4] \n" 140 " brne %1, %2, 3f \n" 141 "2: scond %3, [%4] \n" 142 " bnz 1b \n" 143 #else 144 "1: ld %1, [%4] \n" 145 " brne %1, %2, 3f \n" 146 "2: st %3, [%4] \n" 147 #endif 148 "3: \n" 149 " .section .fixup,\"ax\" \n" 150 "4: mov %0, %5 \n" 151 " j 3b \n" 152 " .previous \n" 153 " .section __ex_table,\"a\" \n" 154 " .align 4 \n" 155 " .word 1b, 4b \n" 156 " .word 2b, 4b \n" 157 " .previous\n" 158 : "+&r"(ret), "=&r"(existval) 159 : "r"(expval), "r"(newval), "r"(uaddr), "ir"(-EFAULT) 160 : "cc", "memory"); 161 162 smp_mb(); 163 164 #ifndef CONFIG_ARC_HAS_LLSC 165 preempt_enable(); 166 #endif 167 *uval = existval; 168 return ret; 169 } 170 171 #endif 172