1fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek#ifndef _ASM_MICROBLAZE_FUTEX_H
2fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek#define _ASM_MICROBLAZE_FUTEX_H
3fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
4fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek#ifdef __KERNEL__
5fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
6fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek#include <linux/futex.h>
7fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek#include <linux/uaccess.h>
8fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek#include <asm/errno.h>
9fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
10fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
11fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek({									\
12fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	__asm__ __volatile__ (						\
13fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			"1:	lwx	%0, %2, r0; "			\
14fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				insn					\
15fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			"2:	swx	%1, %2, r0;			\
16fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				addic	%1, r0, 0;			\
17fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				bnei	%1, 1b;				\
18fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			3:						\
19fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			.section .fixup,\"ax\";				\
20fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			4:	brid	3b;				\
21fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				addik	%1, r0, %3;			\
22fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			.previous;					\
23fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			.section __ex_table,\"a\";			\
24fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			.word	1b,4b,2b,4b;				\
25fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			.previous;"					\
26fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	: "=&r" (oldval), "=&r" (ret)					\
278cf662ed3ef190fddc186bb5b1cd75eb3880d5a9Michal Simek	: "r" (uaddr), "i" (-EFAULT), "r" (oparg)			\
28fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	);								\
29fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek})
30fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
31fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simekstatic inline int
328d7718aa082aaf30a0b4989e1f04858952f941bcMichel Lespinassefutex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
33fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek{
34fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	int op = (encoded_op >> 28) & 7;
35fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	int cmp = (encoded_op >> 24) & 15;
36fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	int oparg = (encoded_op << 8) >> 20;
37fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	int cmparg = (encoded_op << 20) >> 20;
38fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	int oldval = 0, ret;
39fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
40fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		oparg = 1 << oparg;
41fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
428d7718aa082aaf30a0b4989e1f04858952f941bcMichel Lespinasse	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
43fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		return -EFAULT;
44fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
45fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	pagefault_disable();
46fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
47fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	switch (op) {
48fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	case FUTEX_OP_SET:
49fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		__futex_atomic_op("or %1,%4,%4;", ret, oldval, uaddr, oparg);
50fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		break;
51fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	case FUTEX_OP_ADD:
52fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		__futex_atomic_op("add %1,%0,%4;", ret, oldval, uaddr, oparg);
53fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		break;
54fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	case FUTEX_OP_OR:
55fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		__futex_atomic_op("or %1,%0,%4;", ret, oldval, uaddr, oparg);
56fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		break;
57fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	case FUTEX_OP_ANDN:
584bb30baa6d5e7660c06e3b50d8a8a76d402c7170Michal Simek		__futex_atomic_op("andn %1,%0,%4;", ret, oldval, uaddr, oparg);
59fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		break;
60fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	case FUTEX_OP_XOR:
61fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		__futex_atomic_op("xor %1,%0,%4;", ret, oldval, uaddr, oparg);
62fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		break;
63fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	default:
64fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		ret = -ENOSYS;
65fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	}
66fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
67fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	pagefault_enable();
68fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
69fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	if (!ret) {
70fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		switch (cmp) {
71fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		case FUTEX_OP_CMP_EQ:
72fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			ret = (oldval == cmparg);
73fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			break;
74fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		case FUTEX_OP_CMP_NE:
75fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			ret = (oldval != cmparg);
76fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			break;
77fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		case FUTEX_OP_CMP_LT:
78fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			ret = (oldval < cmparg);
79fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			break;
80fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		case FUTEX_OP_CMP_GE:
81fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			ret = (oldval >= cmparg);
82fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			break;
83fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		case FUTEX_OP_CMP_LE:
84fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			ret = (oldval <= cmparg);
85fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			break;
86fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		case FUTEX_OP_CMP_GT:
87fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			ret = (oldval > cmparg);
88fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			break;
89fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		default:
90fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek			ret = -ENOSYS;
91fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		}
92fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	}
93fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek	return ret;
94fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek}
95fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
96fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simekstatic inline int
978d7718aa082aaf30a0b4989e1f04858952f941bcMichel Lespinassefutex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
988d7718aa082aaf30a0b4989e1f04858952f941bcMichel Lespinasse			      u32 oldval, u32 newval)
99fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek{
1008d7718aa082aaf30a0b4989e1f04858952f941bcMichel Lespinasse	int ret = 0, cmp;
1018d7718aa082aaf30a0b4989e1f04858952f941bcMichel Lespinasse	u32 prev;
102fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
1038d7718aa082aaf30a0b4989e1f04858952f941bcMichel Lespinasse	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
104fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		return -EFAULT;
105fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
10637a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse	__asm__ __volatile__ ("1:	lwx	%1, %3, r0;		\
10737a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse					cmp	%2, %1, %4;		\
10837a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse					beqi	%2, 3f;			\
10937a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse				2:	swx	%5, %3, r0;		\
11037a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse					addic	%2, r0, 0;		\
11137a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse					bnei	%2, 1b;			\
112fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				3:					\
113fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				.section .fixup,\"ax\";			\
114fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				4:	brid	3b;			\
11537a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse					addik	%0, r0, %6;		\
116fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				.previous;				\
117fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				.section __ex_table,\"a\";		\
118fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				.word	1b,4b,2b,4b;			\
119fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek				.previous;"				\
12037a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse		: "+r" (ret), "=&r" (prev), "=&r"(cmp)	\
121fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek		: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
122fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
12337a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse	*uval = prev;
12437a9d912b24f96a0591773e6e6c3642991ae5a70Michel Lespinasse	return ret;
125fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek}
126fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
127fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek#endif /* __KERNEL__ */
128fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek
129fd3db0a675a35f28b08e47e8ed1a7a7f158467c2Michal Simek#endif
130