#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__(                                   \
                : "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)
 
        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:
                : 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;
 
 #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(                             \
 
        return ret;
 #else
-       return -ENOSYS;
+       return arch_futex_atomic_op_inuser_local(op, oparg, oval, uaddr);
 #endif
 }
 
 
        return ret;
 #else
-       return -ENOSYS;
+       return futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval);
 #endif
 }
 
 
 #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.
  *
  * -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;
 }
 
 /**
- * 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
  * 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;
        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