18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License
58c2ecf20Sopenharmony_ci * version 2.  This program is licensed "as is" without any warranty of any
68c2ecf20Sopenharmony_ci * kind, whether express or implied.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#ifndef __ASM_OPENRISC_ATOMIC_H
108c2ecf20Sopenharmony_ci#define __ASM_OPENRISC_ATOMIC_H
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/types.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/* Atomically perform op with v->counter and i */
158c2ecf20Sopenharmony_ci#define ATOMIC_OP(op)							\
168c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v)			\
178c2ecf20Sopenharmony_ci{									\
188c2ecf20Sopenharmony_ci	int tmp;							\
198c2ecf20Sopenharmony_ci									\
208c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
218c2ecf20Sopenharmony_ci		"1:	l.lwa	%0,0(%1)	\n"			\
228c2ecf20Sopenharmony_ci		"	l." #op " %0,%0,%2	\n"			\
238c2ecf20Sopenharmony_ci		"	l.swa	0(%1),%0	\n"			\
248c2ecf20Sopenharmony_ci		"	l.bnf	1b		\n"			\
258c2ecf20Sopenharmony_ci		"	 l.nop			\n"			\
268c2ecf20Sopenharmony_ci		: "=&r"(tmp)						\
278c2ecf20Sopenharmony_ci		: "r"(&v->counter), "r"(i)				\
288c2ecf20Sopenharmony_ci		: "cc", "memory");					\
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* Atomically perform op with v->counter and i, return the result */
328c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op)						\
338c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t *v)		\
348c2ecf20Sopenharmony_ci{									\
358c2ecf20Sopenharmony_ci	int tmp;							\
368c2ecf20Sopenharmony_ci									\
378c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
388c2ecf20Sopenharmony_ci		"1:	l.lwa	%0,0(%1)	\n"			\
398c2ecf20Sopenharmony_ci		"	l." #op " %0,%0,%2	\n"			\
408c2ecf20Sopenharmony_ci		"	l.swa	0(%1),%0	\n"			\
418c2ecf20Sopenharmony_ci		"	l.bnf	1b		\n"			\
428c2ecf20Sopenharmony_ci		"	 l.nop			\n"			\
438c2ecf20Sopenharmony_ci		: "=&r"(tmp)						\
448c2ecf20Sopenharmony_ci		: "r"(&v->counter), "r"(i)				\
458c2ecf20Sopenharmony_ci		: "cc", "memory");					\
468c2ecf20Sopenharmony_ci									\
478c2ecf20Sopenharmony_ci	return tmp;							\
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* Atomically perform op with v->counter and i, return orig v->counter */
518c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
528c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t *v)			\
538c2ecf20Sopenharmony_ci{									\
548c2ecf20Sopenharmony_ci	int tmp, old;							\
558c2ecf20Sopenharmony_ci									\
568c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
578c2ecf20Sopenharmony_ci		"1:	l.lwa	%0,0(%2)	\n"			\
588c2ecf20Sopenharmony_ci		"	l." #op " %1,%0,%3	\n"			\
598c2ecf20Sopenharmony_ci		"	l.swa	0(%2),%1	\n"			\
608c2ecf20Sopenharmony_ci		"	l.bnf	1b		\n"			\
618c2ecf20Sopenharmony_ci		"	 l.nop			\n"			\
628c2ecf20Sopenharmony_ci		: "=&r"(old), "=&r"(tmp)				\
638c2ecf20Sopenharmony_ci		: "r"(&v->counter), "r"(i)				\
648c2ecf20Sopenharmony_ci		: "cc", "memory");					\
658c2ecf20Sopenharmony_ci									\
668c2ecf20Sopenharmony_ci	return old;							\
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(add)
708c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(sub)
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(add)
738c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(sub)
748c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(and)
758c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(or)
768c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(xor)
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciATOMIC_OP(and)
798c2ecf20Sopenharmony_ciATOMIC_OP(or)
808c2ecf20Sopenharmony_ciATOMIC_OP(xor)
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP
838c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN
848c2ecf20Sopenharmony_ci#undef ATOMIC_OP
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define atomic_add_return	atomic_add_return
878c2ecf20Sopenharmony_ci#define atomic_sub_return	atomic_sub_return
888c2ecf20Sopenharmony_ci#define atomic_fetch_add	atomic_fetch_add
898c2ecf20Sopenharmony_ci#define atomic_fetch_sub	atomic_fetch_sub
908c2ecf20Sopenharmony_ci#define atomic_fetch_and	atomic_fetch_and
918c2ecf20Sopenharmony_ci#define atomic_fetch_or		atomic_fetch_or
928c2ecf20Sopenharmony_ci#define atomic_fetch_xor	atomic_fetch_xor
938c2ecf20Sopenharmony_ci#define atomic_and	atomic_and
948c2ecf20Sopenharmony_ci#define atomic_or	atomic_or
958c2ecf20Sopenharmony_ci#define atomic_xor	atomic_xor
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/*
988c2ecf20Sopenharmony_ci * Atomically add a to v->counter as long as v is not already u.
998c2ecf20Sopenharmony_ci * Returns the original value at v->counter.
1008c2ecf20Sopenharmony_ci *
1018c2ecf20Sopenharmony_ci * This is often used through atomic_inc_not_zero()
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_cistatic inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	int old, tmp;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1088c2ecf20Sopenharmony_ci		"1:	l.lwa %0, 0(%2)		\n"
1098c2ecf20Sopenharmony_ci		"	l.sfeq %0, %4		\n"
1108c2ecf20Sopenharmony_ci		"	l.bf 2f			\n"
1118c2ecf20Sopenharmony_ci		"	 l.add %1, %0, %3	\n"
1128c2ecf20Sopenharmony_ci		"	l.swa 0(%2), %1		\n"
1138c2ecf20Sopenharmony_ci		"	l.bnf 1b		\n"
1148c2ecf20Sopenharmony_ci		"	 l.nop			\n"
1158c2ecf20Sopenharmony_ci		"2:				\n"
1168c2ecf20Sopenharmony_ci		: "=&r"(old), "=&r" (tmp)
1178c2ecf20Sopenharmony_ci		: "r"(&v->counter), "r"(a), "r"(u)
1188c2ecf20Sopenharmony_ci		: "cc", "memory");
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return old;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci#define atomic_fetch_add_unless	atomic_fetch_add_unless
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci#include <asm-generic/atomic.h>
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci#endif /* __ASM_OPENRISC_ATOMIC_H */
127