ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/linux/arch/arm/include/asm/futex.h b/marvell/linux/arch/arm/include/asm/futex.h
new file mode 100644
index 0000000..fdc4ae3
--- /dev/null
+++ b/marvell/linux/arch/arm/include/asm/futex.h
@@ -0,0 +1,179 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM_FUTEX_H
+#define _ASM_ARM_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <linux/uaccess.h>
+#include <asm/errno.h>
+
+#define __futex_atomic_ex_table(err_reg)			\
+	"3:\n"							\
+	"	.pushsection __ex_table,\"a\"\n"		\
+	"	.align	3\n"					\
+	"	.long	1b, 4f, 2b, 4f\n"			\
+	"	.popsection\n"					\
+	"	.pushsection .text.fixup,\"ax\"\n"		\
+	"	.align	2\n"					\
+	"4:	mov	%0, " err_reg "\n"			\
+	"	b	3b\n"					\
+	"	.popsection"
+
+#ifdef CONFIG_SMP
+
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg)	\
+({								\
+	unsigned int __ua_flags;				\
+	smp_mb();						\
+	prefetchw(uaddr);					\
+	__ua_flags = uaccess_save_and_enable();			\
+	__asm__ __volatile__(					\
+	"1:	ldrex	%1, [%3]\n"				\
+	"	" insn "\n"					\
+	"2:	strex	%2, %0, [%3]\n"				\
+	"	teq	%2, #0\n"				\
+	"	bne	1b\n"					\
+	"	mov	%0, #0\n"				\
+	__futex_atomic_ex_table("%5")				\
+	: "=&r" (ret), "=&r" (oldval), "=&r" (tmp)		\
+	: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)		\
+	: "cc", "memory");					\
+	uaccess_restore(__ua_flags);				\
+})
+
+static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+			      u32 oldval, u32 newval)
+{
+	unsigned int __ua_flags;
+	int ret;
+	u32 val;
+
+	if (!access_ok(uaddr, sizeof(u32)))
+		return -EFAULT;
+
+	smp_mb();
+	/* Prefetching cannot fault */
+	prefetchw(uaddr);
+	__ua_flags = uaccess_save_and_enable();
+	__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
+	"1:	ldrex	%1, [%4]\n"
+	"	teq	%1, %2\n"
+	"	ite	eq	@ explicit IT needed for the 2b label\n"
+	"2:	strexeq	%0, %3, [%4]\n"
+	"	movne	%0, #0\n"
+	"	teq	%0, #0\n"
+	"	bne	1b\n"
+	__futex_atomic_ex_table("%5")
+	: "=&r" (ret), "=&r" (val)
+	: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
+	: "cc", "memory");
+	uaccess_restore(__ua_flags);
+	smp_mb();
+
+	*uval = val;
+	return ret;
+}
+
+#else /* !SMP, we can work around lack of atomic ops by disabling preemption */
+
+#include <linux/preempt.h>
+#include <asm/domain.h>
+
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg)	\
+({								\
+	unsigned int __ua_flags = uaccess_save_and_enable();	\
+	__asm__ __volatile__(					\
+	"1:	" TUSER(ldr) "	%1, [%3]\n"			\
+	"	" insn "\n"					\
+	"2:	" TUSER(str) "	%0, [%3]\n"			\
+	"	mov	%0, #0\n"				\
+	__futex_atomic_ex_table("%5")				\
+	: "=&r" (ret), "=&r" (oldval), "=&r" (tmp)		\
+	: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)		\
+	: "cc", "memory");					\
+	uaccess_restore(__ua_flags);				\
+})
+
+static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+			      u32 oldval, u32 newval)
+{
+	unsigned int __ua_flags;
+	int ret = 0;
+	u32 val;
+
+	if (!access_ok(uaddr, sizeof(u32)))
+		return -EFAULT;
+
+	preempt_disable();
+	__ua_flags = uaccess_save_and_enable();
+	__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
+	"	.syntax unified\n"
+	"1:	" TUSER(ldr) "	%1, [%4]\n"
+	"	teq	%1, %2\n"
+	"	it	eq	@ explicit IT needed for the 2b label\n"
+	"2:	" TUSERCOND(str, eq) "	%3, [%4]\n"
+	__futex_atomic_ex_table("%5")
+	: "+r" (ret), "=&r" (val)
+	: "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
+	: "cc", "memory");
+	uaccess_restore(__ua_flags);
+
+	*uval = val;
+	preempt_enable();
+
+	return ret;
+}
+
+#endif /* !SMP */
+
+static inline int
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+{
+	int oldval = 0, ret, tmp;
+
+#ifndef CONFIG_SMP
+	preempt_disable();
+#endif
+	pagefault_disable();
+
+	switch (op) {
+	case FUTEX_OP_SET:
+		__futex_atomic_op("mov	%0, %4", ret, oldval, tmp, uaddr, oparg);
+		break;
+	case FUTEX_OP_ADD:
+		__futex_atomic_op("add	%0, %1, %4", ret, oldval, tmp, uaddr, oparg);
+		break;
+	case FUTEX_OP_OR:
+		__futex_atomic_op("orr	%0, %1, %4", ret, oldval, tmp, uaddr, oparg);
+		break;
+	case FUTEX_OP_ANDN:
+		__futex_atomic_op("and	%0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
+		break;
+	case FUTEX_OP_XOR:
+		__futex_atomic_op("eor	%0, %1, %4", ret, oldval, tmp, uaddr, oparg);
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+
+	pagefault_enable();
+#ifndef CONFIG_SMP
+	preempt_enable();
+#endif
+
+	/*
+	 * Store unconditionally. If ret != 0 the extra store is the least
+	 * of the worries but GCC cannot figure out that __futex_atomic_op()
+	 * is either setting ret to -EFAULT or storing the old value in
+	 * oldval which results in a uninitialized warning at the call site.
+	 */
+	*oval = oldval;
+
+	return ret;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_ARM_FUTEX_H */