1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __ASM_SH_FUTEX_H 3 #define __ASM_SH_FUTEX_H 4 5 #include <linux/futex.h> 6 #include <linux/uaccess.h> 7 #include <asm/errno.h> 8 9 #if !defined(CONFIG_SMP) 10 #include <asm/futex-irq.h> 11 #elif defined(CONFIG_CPU_J2) 12 #include <asm/futex-cas.h> 13 #elif defined(CONFIG_CPU_SH4A) 14 #include <asm/futex-llsc.h> 15 #else 16 #error SMP not supported on this configuration. 17 #endif 18 19 static inline int 20 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 21 u32 oldval, u32 newval) 22 { 23 if (!access_ok(uaddr, sizeof(u32))) 24 return -EFAULT; 25 26 return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval); 27 } 28 29 static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, 30 u32 __user *uaddr) 31 { 32 u32 oldval, newval, prev; 33 int ret; 34 35 do { 36 ret = get_user(oldval, uaddr); 37 38 if (ret) break; 39 40 switch (op) { 41 case FUTEX_OP_SET: 42 newval = oparg; 43 break; 44 case FUTEX_OP_ADD: 45 newval = oldval + oparg; 46 break; 47 case FUTEX_OP_OR: 48 newval = oldval | oparg; 49 break; 50 case FUTEX_OP_ANDN: 51 newval = oldval & ~oparg; 52 break; 53 case FUTEX_OP_XOR: 54 newval = oldval ^ oparg; 55 break; 56 default: 57 ret = -ENOSYS; 58 break; 59 } 60 61 if (ret) break; 62 63 ret = futex_atomic_cmpxchg_inatomic(&prev, uaddr, oldval, newval); 64 } while (!ret && prev != oldval); 65 66 if (!ret) 67 *oval = oldval; 68 69 return ret; 70 } 71 72 #endif /* __ASM_SH_FUTEX_H */ 73