18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * include/asm-xtensa/atomic.h
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Atomic operations that C can't guarantee us.  Useful for resource counting..
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
78c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
88c2ecf20Sopenharmony_ci * for more details.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2008 Tensilica Inc.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#ifndef _XTENSA_ATOMIC_H
148c2ecf20Sopenharmony_ci#define _XTENSA_ATOMIC_H
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/stringify.h>
178c2ecf20Sopenharmony_ci#include <linux/types.h>
188c2ecf20Sopenharmony_ci#include <asm/processor.h>
198c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h>
208c2ecf20Sopenharmony_ci#include <asm/barrier.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * This Xtensa implementation assumes that the right mechanism
248c2ecf20Sopenharmony_ci * for exclusion is for locking interrupts to level EXCM_LEVEL.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Locking interrupts looks like this:
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci *    rsil a15, TOPLEVEL
298c2ecf20Sopenharmony_ci *    <code>
308c2ecf20Sopenharmony_ci *    wsr  a15, PS
318c2ecf20Sopenharmony_ci *    rsync
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * Note that a15 is used here because the register allocation
348c2ecf20Sopenharmony_ci * done by the compiler is not guaranteed and a window overflow
358c2ecf20Sopenharmony_ci * may not occur between the rsil and wsr instructions. By using
368c2ecf20Sopenharmony_ci * a15 in the rsil, the machine is guaranteed to be in a state
378c2ecf20Sopenharmony_ci * where no register reference will cause an overflow.
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/**
418c2ecf20Sopenharmony_ci * atomic_read - read atomic variable
428c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * Atomically reads the value of @v.
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_ci#define atomic_read(v)		READ_ONCE((v)->counter)
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/**
498c2ecf20Sopenharmony_ci * atomic_set - set atomic variable
508c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t
518c2ecf20Sopenharmony_ci * @i: required value
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * Atomically sets the value of @v to @i.
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_ci#define atomic_set(v,i)		WRITE_ONCE((v)->counter, (i))
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#if XCHAL_HAVE_EXCLUSIVE
588c2ecf20Sopenharmony_ci#define ATOMIC_OP(op)							\
598c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v)			\
608c2ecf20Sopenharmony_ci{									\
618c2ecf20Sopenharmony_ci	unsigned long tmp;						\
628c2ecf20Sopenharmony_ci	int result;							\
638c2ecf20Sopenharmony_ci									\
648c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
658c2ecf20Sopenharmony_ci			"1:     l32ex   %[tmp], %[addr]\n"		\
668c2ecf20Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
678c2ecf20Sopenharmony_ci			"       s32ex   %[result], %[addr]\n"		\
688c2ecf20Sopenharmony_ci			"       getex   %[result]\n"			\
698c2ecf20Sopenharmony_ci			"       beqz    %[result], 1b\n"		\
708c2ecf20Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp)	\
718c2ecf20Sopenharmony_ci			: [i] "a" (i), [addr] "a" (v)			\
728c2ecf20Sopenharmony_ci			: "memory"					\
738c2ecf20Sopenharmony_ci			);						\
748c2ecf20Sopenharmony_ci}									\
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op)						\
778c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t *v)		\
788c2ecf20Sopenharmony_ci{									\
798c2ecf20Sopenharmony_ci	unsigned long tmp;						\
808c2ecf20Sopenharmony_ci	int result;							\
818c2ecf20Sopenharmony_ci									\
828c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
838c2ecf20Sopenharmony_ci			"1:     l32ex   %[tmp], %[addr]\n"		\
848c2ecf20Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
858c2ecf20Sopenharmony_ci			"       s32ex   %[result], %[addr]\n"		\
868c2ecf20Sopenharmony_ci			"       getex   %[result]\n"			\
878c2ecf20Sopenharmony_ci			"       beqz    %[result], 1b\n"		\
888c2ecf20Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
898c2ecf20Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp)	\
908c2ecf20Sopenharmony_ci			: [i] "a" (i), [addr] "a" (v)			\
918c2ecf20Sopenharmony_ci			: "memory"					\
928c2ecf20Sopenharmony_ci			);						\
938c2ecf20Sopenharmony_ci									\
948c2ecf20Sopenharmony_ci	return result;							\
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
988c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t *v)			\
998c2ecf20Sopenharmony_ci{									\
1008c2ecf20Sopenharmony_ci	unsigned long tmp;						\
1018c2ecf20Sopenharmony_ci	int result;							\
1028c2ecf20Sopenharmony_ci									\
1038c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
1048c2ecf20Sopenharmony_ci			"1:     l32ex   %[tmp], %[addr]\n"		\
1058c2ecf20Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
1068c2ecf20Sopenharmony_ci			"       s32ex   %[result], %[addr]\n"		\
1078c2ecf20Sopenharmony_ci			"       getex   %[result]\n"			\
1088c2ecf20Sopenharmony_ci			"       beqz    %[result], 1b\n"		\
1098c2ecf20Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp)	\
1108c2ecf20Sopenharmony_ci			: [i] "a" (i), [addr] "a" (v)			\
1118c2ecf20Sopenharmony_ci			: "memory"					\
1128c2ecf20Sopenharmony_ci			);						\
1138c2ecf20Sopenharmony_ci									\
1148c2ecf20Sopenharmony_ci	return tmp;							\
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#elif XCHAL_HAVE_S32C1I
1188c2ecf20Sopenharmony_ci#define ATOMIC_OP(op)							\
1198c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t * v)			\
1208c2ecf20Sopenharmony_ci{									\
1218c2ecf20Sopenharmony_ci	unsigned long tmp;						\
1228c2ecf20Sopenharmony_ci	int result;							\
1238c2ecf20Sopenharmony_ci									\
1248c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
1258c2ecf20Sopenharmony_ci			"1:     l32i    %[tmp], %[mem]\n"		\
1268c2ecf20Sopenharmony_ci			"       wsr     %[tmp], scompare1\n"		\
1278c2ecf20Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
1288c2ecf20Sopenharmony_ci			"       s32c1i  %[result], %[mem]\n"		\
1298c2ecf20Sopenharmony_ci			"       bne     %[result], %[tmp], 1b\n"	\
1308c2ecf20Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp),	\
1318c2ecf20Sopenharmony_ci			  [mem] "+m" (*v)				\
1328c2ecf20Sopenharmony_ci			: [i] "a" (i)					\
1338c2ecf20Sopenharmony_ci			: "memory"					\
1348c2ecf20Sopenharmony_ci			);						\
1358c2ecf20Sopenharmony_ci}									\
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op)						\
1388c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t * v)		\
1398c2ecf20Sopenharmony_ci{									\
1408c2ecf20Sopenharmony_ci	unsigned long tmp;						\
1418c2ecf20Sopenharmony_ci	int result;							\
1428c2ecf20Sopenharmony_ci									\
1438c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
1448c2ecf20Sopenharmony_ci			"1:     l32i    %[tmp], %[mem]\n"		\
1458c2ecf20Sopenharmony_ci			"       wsr     %[tmp], scompare1\n"		\
1468c2ecf20Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
1478c2ecf20Sopenharmony_ci			"       s32c1i  %[result], %[mem]\n"		\
1488c2ecf20Sopenharmony_ci			"       bne     %[result], %[tmp], 1b\n"	\
1498c2ecf20Sopenharmony_ci			"       " #op " %[result], %[result], %[i]\n"	\
1508c2ecf20Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp),	\
1518c2ecf20Sopenharmony_ci			  [mem] "+m" (*v)				\
1528c2ecf20Sopenharmony_ci			: [i] "a" (i)					\
1538c2ecf20Sopenharmony_ci			: "memory"					\
1548c2ecf20Sopenharmony_ci			);						\
1558c2ecf20Sopenharmony_ci									\
1568c2ecf20Sopenharmony_ci	return result;							\
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
1608c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t * v)		\
1618c2ecf20Sopenharmony_ci{									\
1628c2ecf20Sopenharmony_ci	unsigned long tmp;						\
1638c2ecf20Sopenharmony_ci	int result;							\
1648c2ecf20Sopenharmony_ci									\
1658c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
1668c2ecf20Sopenharmony_ci			"1:     l32i    %[tmp], %[mem]\n"		\
1678c2ecf20Sopenharmony_ci			"       wsr     %[tmp], scompare1\n"		\
1688c2ecf20Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
1698c2ecf20Sopenharmony_ci			"       s32c1i  %[result], %[mem]\n"		\
1708c2ecf20Sopenharmony_ci			"       bne     %[result], %[tmp], 1b\n"	\
1718c2ecf20Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp),	\
1728c2ecf20Sopenharmony_ci			  [mem] "+m" (*v)				\
1738c2ecf20Sopenharmony_ci			: [i] "a" (i)					\
1748c2ecf20Sopenharmony_ci			: "memory"					\
1758c2ecf20Sopenharmony_ci			);						\
1768c2ecf20Sopenharmony_ci									\
1778c2ecf20Sopenharmony_ci	return result;							\
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci#else /* XCHAL_HAVE_S32C1I */
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci#define ATOMIC_OP(op)							\
1838c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t * v)			\
1848c2ecf20Sopenharmony_ci{									\
1858c2ecf20Sopenharmony_ci	unsigned int vval;						\
1868c2ecf20Sopenharmony_ci									\
1878c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
1888c2ecf20Sopenharmony_ci			"       rsil    a15, "__stringify(TOPLEVEL)"\n"	\
1898c2ecf20Sopenharmony_ci			"       l32i    %[result], %[mem]\n"		\
1908c2ecf20Sopenharmony_ci			"       " #op " %[result], %[result], %[i]\n"	\
1918c2ecf20Sopenharmony_ci			"       s32i    %[result], %[mem]\n"		\
1928c2ecf20Sopenharmony_ci			"       wsr     a15, ps\n"			\
1938c2ecf20Sopenharmony_ci			"       rsync\n"				\
1948c2ecf20Sopenharmony_ci			: [result] "=&a" (vval), [mem] "+m" (*v)	\
1958c2ecf20Sopenharmony_ci			: [i] "a" (i)					\
1968c2ecf20Sopenharmony_ci			: "a15", "memory"				\
1978c2ecf20Sopenharmony_ci			);						\
1988c2ecf20Sopenharmony_ci}									\
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op)						\
2018c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t * v)		\
2028c2ecf20Sopenharmony_ci{									\
2038c2ecf20Sopenharmony_ci	unsigned int vval;						\
2048c2ecf20Sopenharmony_ci									\
2058c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
2068c2ecf20Sopenharmony_ci			"       rsil    a15,"__stringify(TOPLEVEL)"\n"	\
2078c2ecf20Sopenharmony_ci			"       l32i    %[result], %[mem]\n"		\
2088c2ecf20Sopenharmony_ci			"       " #op " %[result], %[result], %[i]\n"	\
2098c2ecf20Sopenharmony_ci			"       s32i    %[result], %[mem]\n"		\
2108c2ecf20Sopenharmony_ci			"       wsr     a15, ps\n"			\
2118c2ecf20Sopenharmony_ci			"       rsync\n"				\
2128c2ecf20Sopenharmony_ci			: [result] "=&a" (vval), [mem] "+m" (*v)	\
2138c2ecf20Sopenharmony_ci			: [i] "a" (i)					\
2148c2ecf20Sopenharmony_ci			: "a15", "memory"				\
2158c2ecf20Sopenharmony_ci			);						\
2168c2ecf20Sopenharmony_ci									\
2178c2ecf20Sopenharmony_ci	return vval;							\
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
2218c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t * v)		\
2228c2ecf20Sopenharmony_ci{									\
2238c2ecf20Sopenharmony_ci	unsigned int tmp, vval;						\
2248c2ecf20Sopenharmony_ci									\
2258c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
2268c2ecf20Sopenharmony_ci			"       rsil    a15,"__stringify(TOPLEVEL)"\n"	\
2278c2ecf20Sopenharmony_ci			"       l32i    %[result], %[mem]\n"		\
2288c2ecf20Sopenharmony_ci			"       " #op " %[tmp], %[result], %[i]\n"	\
2298c2ecf20Sopenharmony_ci			"       s32i    %[tmp], %[mem]\n"		\
2308c2ecf20Sopenharmony_ci			"       wsr     a15, ps\n"			\
2318c2ecf20Sopenharmony_ci			"       rsync\n"				\
2328c2ecf20Sopenharmony_ci			: [result] "=&a" (vval), [tmp] "=&a" (tmp),	\
2338c2ecf20Sopenharmony_ci			  [mem] "+m" (*v)				\
2348c2ecf20Sopenharmony_ci			: [i] "a" (i)					\
2358c2ecf20Sopenharmony_ci			: "a15", "memory"				\
2368c2ecf20Sopenharmony_ci			);						\
2378c2ecf20Sopenharmony_ci									\
2388c2ecf20Sopenharmony_ci	return vval;							\
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci#endif /* XCHAL_HAVE_S32C1I */
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) ATOMIC_OP_RETURN(op)
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ciATOMIC_OPS(add)
2468c2ecf20Sopenharmony_ciATOMIC_OPS(sub)
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci#undef ATOMIC_OPS
2498c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ciATOMIC_OPS(and)
2528c2ecf20Sopenharmony_ciATOMIC_OPS(or)
2538c2ecf20Sopenharmony_ciATOMIC_OPS(xor)
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci#undef ATOMIC_OPS
2568c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP
2578c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN
2588c2ecf20Sopenharmony_ci#undef ATOMIC_OP
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
2618c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci#endif /* _XTENSA_ATOMIC_H */
264