diff options
-rw-r--r-- | arch/mips/include/asm/futex.h | 29 | ||||
-rw-r--r-- | arch/xtensa/include/asm/futex.h | 8 | ||||
-rw-r--r-- | include/asm-generic/futex.h | 31 | ||||
-rw-r--r-- | init/Kconfig | 1 |
4 files changed, 36 insertions, 33 deletions
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h index d85248404c52..9287110cb06d 100644 --- a/arch/mips/include/asm/futex.h +++ b/arch/mips/include/asm/futex.h @@ -19,7 +19,11 @@ #include <asm/sync.h> #include <asm/war.h> -#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ +#define arch_futex_atomic_op_inuser arch_futex_atomic_op_inuser +#define futex_atomic_cmpxchg_inatomic futex_atomic_cmpxchg_inatomic +#include <asm-generic/futex.h> + +#define __futex_atomic_op(op, insn, ret, oldval, uaddr, oparg) \ { \ if (cpu_has_llsc && IS_ENABLED(CONFIG_WAR_R10000_LLSC)) { \ __asm__ __volatile__( \ @@ -80,9 +84,11 @@ : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \ "i" (-EFAULT) \ : "memory"); \ - } else \ - ret = -ENOSYS; \ -} + } else { \ + /* fallback for non-SMP */ \ + ret = arch_futex_atomic_op_inuser_local(op, oparg, oval,\ + uaddr); \ + } static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) @@ -94,23 +100,23 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) switch (op) { case FUTEX_OP_SET: - __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg); + __futex_atomic_op(op, "move $1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op("addu $1, %1, %z5", + __futex_atomic_op(op, "addu $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: - __futex_atomic_op("or $1, %1, %z5", + __futex_atomic_op(op, "or $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ANDN: - __futex_atomic_op("and $1, %1, %z5", + __futex_atomic_op(op, "and $1, %1, %z5", ret, oldval, uaddr, ~oparg); break; case FUTEX_OP_XOR: - __futex_atomic_op("xor $1, %1, %z5", + __futex_atomic_op(op, "xor $1, %1, %z5", ret, oldval, uaddr, oparg); break; default: @@ -193,8 +199,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) : "memory"); - } else - return -ENOSYS; + } else { + return futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval); + } *uval = val; return ret; diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h index a1a27b2ea460..fe8f31575ab1 100644 --- a/arch/xtensa/include/asm/futex.h +++ b/arch/xtensa/include/asm/futex.h @@ -16,6 +16,10 @@ #include <linux/uaccess.h> #include <linux/errno.h> +#define arch_futex_atomic_op_inuser arch_futex_atomic_op_inuser +#define futex_atomic_cmpxchg_inatomic futex_atomic_cmpxchg_inatomic +#include <asm-generic/futex.h> + #if XCHAL_HAVE_EXCLUSIVE #define __futex_atomic_op(insn, ret, old, uaddr, arg) \ __asm__ __volatile( \ @@ -105,7 +109,7 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, return ret; #else - return -ENOSYS; + return arch_futex_atomic_op_inuser_local(op, oparg, oval, uaddr); #endif } @@ -156,7 +160,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return ret; #else - return -ENOSYS; + return futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval); #endif } diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h index f4c3470480c7..30e7fa63b5df 100644 --- a/include/asm-generic/futex.h +++ b/include/asm-generic/futex.h @@ -6,15 +6,22 @@ #include <linux/uaccess.h> #include <asm/errno.h> +#ifndef futex_atomic_cmpxchg_inatomic #ifndef CONFIG_SMP /* * The following implementation only for uniprocessor machines. * It relies on preempt_disable() ensuring mutual exclusion. * */ +#define futex_atomic_cmpxchg_inatomic(uval, uaddr, oldval, newval) \ + futex_atomic_cmpxchg_inatomic_local_generic(uval, uaddr, oldval, newval) +#define arch_futex_atomic_op_inuser(op, oparg, oval, uaddr) \ + arch_futex_atomic_op_inuser_local_generic(op, oparg, oval, uaddr) +#endif /* CONFIG_SMP */ +#endif /** - * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant + * arch_futex_atomic_op_inuser_local() - Atomic arithmetic operation with constant * argument and comparison of the previous * futex value with another constant. * @@ -28,7 +35,7 @@ * -ENOSYS - Operation not supported */ static inline int -arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) +futex_atomic_op_inuser_local(int op, u32 oparg, int *oval, u32 __user *uaddr) { int oldval, ret; u32 tmp; @@ -75,7 +82,7 @@ out_pagefault_enable: } /** - * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the + * futex_atomic_cmpxchg_inatomic_local() - Compare and exchange the content of the * uaddr with newval if the current value is * oldval. * @uval: pointer to store content of @uaddr @@ -87,10 +94,9 @@ out_pagefault_enable: * 0 - On success * -EFAULT - User access resulted in a page fault * -EAGAIN - Atomic operation was unable to complete due to contention - * -ENOSYS - Function not implemented (only if !HAVE_FUTEX_CMPXCHG) */ static inline int -futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, +futex_atomic_cmpxchg_inatomic_local(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { u32 val; @@ -112,19 +118,4 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return 0; } -#else -static inline int -arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) -{ - return -ENOSYS; -} - -static inline int -futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, - u32 oldval, u32 newval) -{ - return -ENOSYS; -} - -#endif /* CONFIG_SMP */ #endif diff --git a/init/Kconfig b/init/Kconfig index 036b750e8d8a..3f5aa5063f55 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1579,6 +1579,7 @@ config BASE_FULL config FUTEX bool "Enable futex support" if EXPERT + depends on !(SPARC32 && SMP) default y imply RT_MUTEXES help |