1/*
2 * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
3 *
4 * This file is licensed under the terms of the GNU General Public License
5 * version 2.  This program is licensed "as is" without any warranty of any
6 * kind, whether express or implied.
7 */
8
9#ifndef __ASM_OPENRISC_ATOMIC_H
10#define __ASM_OPENRISC_ATOMIC_H
11
12#include <linux/types.h>
13
14/* Atomically perform op with v->counter and i */
15#define ATOMIC_OP(op)							\
16static inline void atomic_##op(int i, atomic_t *v)			\
17{									\
18	int tmp;							\
19									\
20	__asm__ __volatile__(						\
21		"1:	l.lwa	%0,0(%1)	\n"			\
22		"	l." #op " %0,%0,%2	\n"			\
23		"	l.swa	0(%1),%0	\n"			\
24		"	l.bnf	1b		\n"			\
25		"	 l.nop			\n"			\
26		: "=&r"(tmp)						\
27		: "r"(&v->counter), "r"(i)				\
28		: "cc", "memory");					\
29}
30
31/* Atomically perform op with v->counter and i, return the result */
32#define ATOMIC_OP_RETURN(op)						\
33static inline int atomic_##op##_return(int i, atomic_t *v)		\
34{									\
35	int tmp;							\
36									\
37	__asm__ __volatile__(						\
38		"1:	l.lwa	%0,0(%1)	\n"			\
39		"	l." #op " %0,%0,%2	\n"			\
40		"	l.swa	0(%1),%0	\n"			\
41		"	l.bnf	1b		\n"			\
42		"	 l.nop			\n"			\
43		: "=&r"(tmp)						\
44		: "r"(&v->counter), "r"(i)				\
45		: "cc", "memory");					\
46									\
47	return tmp;							\
48}
49
50/* Atomically perform op with v->counter and i, return orig v->counter */
51#define ATOMIC_FETCH_OP(op)						\
52static inline int atomic_fetch_##op(int i, atomic_t *v)			\
53{									\
54	int tmp, old;							\
55									\
56	__asm__ __volatile__(						\
57		"1:	l.lwa	%0,0(%2)	\n"			\
58		"	l." #op " %1,%0,%3	\n"			\
59		"	l.swa	0(%2),%1	\n"			\
60		"	l.bnf	1b		\n"			\
61		"	 l.nop			\n"			\
62		: "=&r"(old), "=&r"(tmp)				\
63		: "r"(&v->counter), "r"(i)				\
64		: "cc", "memory");					\
65									\
66	return old;							\
67}
68
69ATOMIC_OP_RETURN(add)
70ATOMIC_OP_RETURN(sub)
71
72ATOMIC_FETCH_OP(add)
73ATOMIC_FETCH_OP(sub)
74ATOMIC_FETCH_OP(and)
75ATOMIC_FETCH_OP(or)
76ATOMIC_FETCH_OP(xor)
77
78ATOMIC_OP(and)
79ATOMIC_OP(or)
80ATOMIC_OP(xor)
81
82#undef ATOMIC_FETCH_OP
83#undef ATOMIC_OP_RETURN
84#undef ATOMIC_OP
85
86#define atomic_add_return	atomic_add_return
87#define atomic_sub_return	atomic_sub_return
88#define atomic_fetch_add	atomic_fetch_add
89#define atomic_fetch_sub	atomic_fetch_sub
90#define atomic_fetch_and	atomic_fetch_and
91#define atomic_fetch_or		atomic_fetch_or
92#define atomic_fetch_xor	atomic_fetch_xor
93#define atomic_and	atomic_and
94#define atomic_or	atomic_or
95#define atomic_xor	atomic_xor
96
97/*
98 * Atomically add a to v->counter as long as v is not already u.
99 * Returns the original value at v->counter.
100 *
101 * This is often used through atomic_inc_not_zero()
102 */
103static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
104{
105	int old, tmp;
106
107	__asm__ __volatile__(
108		"1:	l.lwa %0, 0(%2)		\n"
109		"	l.sfeq %0, %4		\n"
110		"	l.bf 2f			\n"
111		"	 l.add %1, %0, %3	\n"
112		"	l.swa 0(%2), %1		\n"
113		"	l.bnf 1b		\n"
114		"	 l.nop			\n"
115		"2:				\n"
116		: "=&r"(old), "=&r" (tmp)
117		: "r"(&v->counter), "r"(a), "r"(u)
118		: "cc", "memory");
119
120	return old;
121}
122#define atomic_fetch_add_unless	atomic_fetch_add_unless
123
124#include <asm-generic/atomic.h>
125
126#endif /* __ASM_OPENRISC_ATOMIC_H */
127