162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_MICROBLAZE_FUTEX_H
362306a36Sopenharmony_ci#define _ASM_MICROBLAZE_FUTEX_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#ifdef __KERNEL__
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/futex.h>
862306a36Sopenharmony_ci#include <linux/uaccess.h>
962306a36Sopenharmony_ci#include <asm/errno.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
1262306a36Sopenharmony_ci({									\
1362306a36Sopenharmony_ci	__asm__ __volatile__ (						\
1462306a36Sopenharmony_ci			"1:	lwx	%0, %2, r0; "			\
1562306a36Sopenharmony_ci				insn					\
1662306a36Sopenharmony_ci			"2:	swx	%1, %2, r0;			\
1762306a36Sopenharmony_ci				addic	%1, r0, 0;			\
1862306a36Sopenharmony_ci				bnei	%1, 1b;				\
1962306a36Sopenharmony_ci			3:						\
2062306a36Sopenharmony_ci			.section .fixup,\"ax\";				\
2162306a36Sopenharmony_ci			4:	brid	3b;				\
2262306a36Sopenharmony_ci				addik	%1, r0, %3;			\
2362306a36Sopenharmony_ci			.previous;					\
2462306a36Sopenharmony_ci			.section __ex_table,\"a\";			\
2562306a36Sopenharmony_ci			.word	1b,4b,2b,4b;				\
2662306a36Sopenharmony_ci			.previous;"					\
2762306a36Sopenharmony_ci	: "=&r" (oldval), "=&r" (ret)					\
2862306a36Sopenharmony_ci	: "r" (uaddr), "i" (-EFAULT), "r" (oparg)			\
2962306a36Sopenharmony_ci	);								\
3062306a36Sopenharmony_ci})
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic inline int
3362306a36Sopenharmony_ciarch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	int oldval = 0, ret;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (!access_ok(uaddr, sizeof(u32)))
3862306a36Sopenharmony_ci		return -EFAULT;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	switch (op) {
4162306a36Sopenharmony_ci	case FUTEX_OP_SET:
4262306a36Sopenharmony_ci		__futex_atomic_op("or %1,%4,%4;", ret, oldval, uaddr, oparg);
4362306a36Sopenharmony_ci		break;
4462306a36Sopenharmony_ci	case FUTEX_OP_ADD:
4562306a36Sopenharmony_ci		__futex_atomic_op("add %1,%0,%4;", ret, oldval, uaddr, oparg);
4662306a36Sopenharmony_ci		break;
4762306a36Sopenharmony_ci	case FUTEX_OP_OR:
4862306a36Sopenharmony_ci		__futex_atomic_op("or %1,%0,%4;", ret, oldval, uaddr, oparg);
4962306a36Sopenharmony_ci		break;
5062306a36Sopenharmony_ci	case FUTEX_OP_ANDN:
5162306a36Sopenharmony_ci		__futex_atomic_op("andn %1,%0,%4;", ret, oldval, uaddr, oparg);
5262306a36Sopenharmony_ci		break;
5362306a36Sopenharmony_ci	case FUTEX_OP_XOR:
5462306a36Sopenharmony_ci		__futex_atomic_op("xor %1,%0,%4;", ret, oldval, uaddr, oparg);
5562306a36Sopenharmony_ci		break;
5662306a36Sopenharmony_ci	default:
5762306a36Sopenharmony_ci		ret = -ENOSYS;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (!ret)
6162306a36Sopenharmony_ci		*oval = oldval;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return ret;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic inline int
6762306a36Sopenharmony_cifutex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
6862306a36Sopenharmony_ci			      u32 oldval, u32 newval)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	int ret = 0, cmp;
7162306a36Sopenharmony_ci	u32 prev;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (!access_ok(uaddr, sizeof(u32)))
7462306a36Sopenharmony_ci		return -EFAULT;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	__asm__ __volatile__ ("1:	lwx	%1, %3, r0;		\
7762306a36Sopenharmony_ci					cmp	%2, %1, %4;		\
7862306a36Sopenharmony_ci					bnei	%2, 3f;			\
7962306a36Sopenharmony_ci				2:	swx	%5, %3, r0;		\
8062306a36Sopenharmony_ci					addic	%2, r0, 0;		\
8162306a36Sopenharmony_ci					bnei	%2, 1b;			\
8262306a36Sopenharmony_ci				3:					\
8362306a36Sopenharmony_ci				.section .fixup,\"ax\";			\
8462306a36Sopenharmony_ci				4:	brid	3b;			\
8562306a36Sopenharmony_ci					addik	%0, r0, %6;		\
8662306a36Sopenharmony_ci				.previous;				\
8762306a36Sopenharmony_ci				.section __ex_table,\"a\";		\
8862306a36Sopenharmony_ci				.word	1b,4b,2b,4b;			\
8962306a36Sopenharmony_ci				.previous;"				\
9062306a36Sopenharmony_ci		: "+r" (ret), "=&r" (prev), "=&r"(cmp)	\
9162306a36Sopenharmony_ci		: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	*uval = prev;
9462306a36Sopenharmony_ci	return ret;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#endif /* __KERNEL__ */
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#endif
100