162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * include/asm-xtensa/atomic.h
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Atomic operations that C can't guarantee us.  Useful for resource counting..
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
762306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
862306a36Sopenharmony_ci * for more details.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Copyright (C) 2001 - 2008 Tensilica Inc.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#ifndef _XTENSA_ATOMIC_H
1462306a36Sopenharmony_ci#define _XTENSA_ATOMIC_H
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/stringify.h>
1762306a36Sopenharmony_ci#include <linux/types.h>
1862306a36Sopenharmony_ci#include <asm/processor.h>
1962306a36Sopenharmony_ci#include <asm/cmpxchg.h>
2062306a36Sopenharmony_ci#include <asm/barrier.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * This Xtensa implementation assumes that the right mechanism
2462306a36Sopenharmony_ci * for exclusion is for locking interrupts to level EXCM_LEVEL.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Locking interrupts looks like this:
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci *    rsil a14, TOPLEVEL
2962306a36Sopenharmony_ci *    <code>
3062306a36Sopenharmony_ci *    wsr  a14, PS
3162306a36Sopenharmony_ci *    rsync
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * Note that a14 is used here because the register allocation
3462306a36Sopenharmony_ci * done by the compiler is not guaranteed and a window overflow
3562306a36Sopenharmony_ci * may not occur between the rsil and wsr instructions. By using
3662306a36Sopenharmony_ci * a14 in the rsil, the machine is guaranteed to be in a state
3762306a36Sopenharmony_ci * where no register reference will cause an overflow.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/**
4162306a36Sopenharmony_ci * atomic_read - read atomic variable
4262306a36Sopenharmony_ci * @v: pointer of type atomic_t
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Atomically reads the value of @v.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ci#define arch_atomic_read(v)		READ_ONCE((v)->counter)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/**
4962306a36Sopenharmony_ci * atomic_set - set atomic variable
5062306a36Sopenharmony_ci * @v: pointer of type atomic_t
5162306a36Sopenharmony_ci * @i: required value
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci * Atomically sets the value of @v to @i.
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ci#define arch_atomic_set(v,i)		WRITE_ONCE((v)->counter, (i))
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#if XCHAL_HAVE_EXCLUSIVE
5862306a36Sopenharmony_ci#define ATOMIC_OP(op)							\
5962306a36Sopenharmony_cistatic inline void arch_atomic_##op(int i, atomic_t *v)			\
6062306a36Sopenharmony_ci{									\
6162306a36Sopenharmony_ci	unsigned long tmp;						\
6262306a36Sopenharmony_ci	int result;							\
6362306a36Sopenharmony_ci									\
6462306a36Sopenharmony_ci	__asm__ __volatile__(						\
6562306a36Sopenharmony_ci			"1:     l32ex   %[tmp], %[addr]\n"		\
6662306a36Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
6762306a36Sopenharmony_ci			"       s32ex   %[result], %[addr]\n"		\
6862306a36Sopenharmony_ci			"       getex   %[result]\n"			\
6962306a36Sopenharmony_ci			"       beqz    %[result], 1b\n"		\
7062306a36Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp)	\
7162306a36Sopenharmony_ci			: [i] "a" (i), [addr] "a" (v)			\
7262306a36Sopenharmony_ci			: "memory"					\
7362306a36Sopenharmony_ci			);						\
7462306a36Sopenharmony_ci}									\
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define ATOMIC_OP_RETURN(op)						\
7762306a36Sopenharmony_cistatic inline int arch_atomic_##op##_return(int i, atomic_t *v)		\
7862306a36Sopenharmony_ci{									\
7962306a36Sopenharmony_ci	unsigned long tmp;						\
8062306a36Sopenharmony_ci	int result;							\
8162306a36Sopenharmony_ci									\
8262306a36Sopenharmony_ci	__asm__ __volatile__(						\
8362306a36Sopenharmony_ci			"1:     l32ex   %[tmp], %[addr]\n"		\
8462306a36Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
8562306a36Sopenharmony_ci			"       s32ex   %[result], %[addr]\n"		\
8662306a36Sopenharmony_ci			"       getex   %[result]\n"			\
8762306a36Sopenharmony_ci			"       beqz    %[result], 1b\n"		\
8862306a36Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
8962306a36Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp)	\
9062306a36Sopenharmony_ci			: [i] "a" (i), [addr] "a" (v)			\
9162306a36Sopenharmony_ci			: "memory"					\
9262306a36Sopenharmony_ci			);						\
9362306a36Sopenharmony_ci									\
9462306a36Sopenharmony_ci	return result;							\
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
9862306a36Sopenharmony_cistatic inline int arch_atomic_fetch_##op(int i, atomic_t *v)		\
9962306a36Sopenharmony_ci{									\
10062306a36Sopenharmony_ci	unsigned long tmp;						\
10162306a36Sopenharmony_ci	int result;							\
10262306a36Sopenharmony_ci									\
10362306a36Sopenharmony_ci	__asm__ __volatile__(						\
10462306a36Sopenharmony_ci			"1:     l32ex   %[tmp], %[addr]\n"		\
10562306a36Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
10662306a36Sopenharmony_ci			"       s32ex   %[result], %[addr]\n"		\
10762306a36Sopenharmony_ci			"       getex   %[result]\n"			\
10862306a36Sopenharmony_ci			"       beqz    %[result], 1b\n"		\
10962306a36Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp)	\
11062306a36Sopenharmony_ci			: [i] "a" (i), [addr] "a" (v)			\
11162306a36Sopenharmony_ci			: "memory"					\
11262306a36Sopenharmony_ci			);						\
11362306a36Sopenharmony_ci									\
11462306a36Sopenharmony_ci	return tmp;							\
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#elif XCHAL_HAVE_S32C1I
11862306a36Sopenharmony_ci#define ATOMIC_OP(op)							\
11962306a36Sopenharmony_cistatic inline void arch_atomic_##op(int i, atomic_t * v)		\
12062306a36Sopenharmony_ci{									\
12162306a36Sopenharmony_ci	unsigned long tmp;						\
12262306a36Sopenharmony_ci	int result;							\
12362306a36Sopenharmony_ci									\
12462306a36Sopenharmony_ci	__asm__ __volatile__(						\
12562306a36Sopenharmony_ci			"1:     l32i    %[tmp], %[mem]\n"		\
12662306a36Sopenharmony_ci			"       wsr     %[tmp], scompare1\n"		\
12762306a36Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
12862306a36Sopenharmony_ci			"       s32c1i  %[result], %[mem]\n"		\
12962306a36Sopenharmony_ci			"       bne     %[result], %[tmp], 1b\n"	\
13062306a36Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp),	\
13162306a36Sopenharmony_ci			  [mem] "+m" (*v)				\
13262306a36Sopenharmony_ci			: [i] "a" (i)					\
13362306a36Sopenharmony_ci			: "memory"					\
13462306a36Sopenharmony_ci			);						\
13562306a36Sopenharmony_ci}									\
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#define ATOMIC_OP_RETURN(op)						\
13862306a36Sopenharmony_cistatic inline int arch_atomic_##op##_return(int i, atomic_t * v)	\
13962306a36Sopenharmony_ci{									\
14062306a36Sopenharmony_ci	unsigned long tmp;						\
14162306a36Sopenharmony_ci	int result;							\
14262306a36Sopenharmony_ci									\
14362306a36Sopenharmony_ci	__asm__ __volatile__(						\
14462306a36Sopenharmony_ci			"1:     l32i    %[tmp], %[mem]\n"		\
14562306a36Sopenharmony_ci			"       wsr     %[tmp], scompare1\n"		\
14662306a36Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
14762306a36Sopenharmony_ci			"       s32c1i  %[result], %[mem]\n"		\
14862306a36Sopenharmony_ci			"       bne     %[result], %[tmp], 1b\n"	\
14962306a36Sopenharmony_ci			"       " #op " %[result], %[result], %[i]\n"	\
15062306a36Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp),	\
15162306a36Sopenharmony_ci			  [mem] "+m" (*v)				\
15262306a36Sopenharmony_ci			: [i] "a" (i)					\
15362306a36Sopenharmony_ci			: "memory"					\
15462306a36Sopenharmony_ci			);						\
15562306a36Sopenharmony_ci									\
15662306a36Sopenharmony_ci	return result;							\
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
16062306a36Sopenharmony_cistatic inline int arch_atomic_fetch_##op(int i, atomic_t * v)		\
16162306a36Sopenharmony_ci{									\
16262306a36Sopenharmony_ci	unsigned long tmp;						\
16362306a36Sopenharmony_ci	int result;							\
16462306a36Sopenharmony_ci									\
16562306a36Sopenharmony_ci	__asm__ __volatile__(						\
16662306a36Sopenharmony_ci			"1:     l32i    %[tmp], %[mem]\n"		\
16762306a36Sopenharmony_ci			"       wsr     %[tmp], scompare1\n"		\
16862306a36Sopenharmony_ci			"       " #op " %[result], %[tmp], %[i]\n"	\
16962306a36Sopenharmony_ci			"       s32c1i  %[result], %[mem]\n"		\
17062306a36Sopenharmony_ci			"       bne     %[result], %[tmp], 1b\n"	\
17162306a36Sopenharmony_ci			: [result] "=&a" (result), [tmp] "=&a" (tmp),	\
17262306a36Sopenharmony_ci			  [mem] "+m" (*v)				\
17362306a36Sopenharmony_ci			: [i] "a" (i)					\
17462306a36Sopenharmony_ci			: "memory"					\
17562306a36Sopenharmony_ci			);						\
17662306a36Sopenharmony_ci									\
17762306a36Sopenharmony_ci	return result;							\
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci#else /* XCHAL_HAVE_S32C1I */
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#define ATOMIC_OP(op)							\
18362306a36Sopenharmony_cistatic inline void arch_atomic_##op(int i, atomic_t * v)		\
18462306a36Sopenharmony_ci{									\
18562306a36Sopenharmony_ci	unsigned int vval;						\
18662306a36Sopenharmony_ci									\
18762306a36Sopenharmony_ci	__asm__ __volatile__(						\
18862306a36Sopenharmony_ci			"       rsil    a14, "__stringify(TOPLEVEL)"\n"	\
18962306a36Sopenharmony_ci			"       l32i    %[result], %[mem]\n"		\
19062306a36Sopenharmony_ci			"       " #op " %[result], %[result], %[i]\n"	\
19162306a36Sopenharmony_ci			"       s32i    %[result], %[mem]\n"		\
19262306a36Sopenharmony_ci			"       wsr     a14, ps\n"			\
19362306a36Sopenharmony_ci			"       rsync\n"				\
19462306a36Sopenharmony_ci			: [result] "=&a" (vval), [mem] "+m" (*v)	\
19562306a36Sopenharmony_ci			: [i] "a" (i)					\
19662306a36Sopenharmony_ci			: "a14", "memory"				\
19762306a36Sopenharmony_ci			);						\
19862306a36Sopenharmony_ci}									\
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci#define ATOMIC_OP_RETURN(op)						\
20162306a36Sopenharmony_cistatic inline int arch_atomic_##op##_return(int i, atomic_t * v)	\
20262306a36Sopenharmony_ci{									\
20362306a36Sopenharmony_ci	unsigned int vval;						\
20462306a36Sopenharmony_ci									\
20562306a36Sopenharmony_ci	__asm__ __volatile__(						\
20662306a36Sopenharmony_ci			"       rsil    a14,"__stringify(TOPLEVEL)"\n"	\
20762306a36Sopenharmony_ci			"       l32i    %[result], %[mem]\n"		\
20862306a36Sopenharmony_ci			"       " #op " %[result], %[result], %[i]\n"	\
20962306a36Sopenharmony_ci			"       s32i    %[result], %[mem]\n"		\
21062306a36Sopenharmony_ci			"       wsr     a14, ps\n"			\
21162306a36Sopenharmony_ci			"       rsync\n"				\
21262306a36Sopenharmony_ci			: [result] "=&a" (vval), [mem] "+m" (*v)	\
21362306a36Sopenharmony_ci			: [i] "a" (i)					\
21462306a36Sopenharmony_ci			: "a14", "memory"				\
21562306a36Sopenharmony_ci			);						\
21662306a36Sopenharmony_ci									\
21762306a36Sopenharmony_ci	return vval;							\
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
22162306a36Sopenharmony_cistatic inline int arch_atomic_fetch_##op(int i, atomic_t * v)		\
22262306a36Sopenharmony_ci{									\
22362306a36Sopenharmony_ci	unsigned int tmp, vval;						\
22462306a36Sopenharmony_ci									\
22562306a36Sopenharmony_ci	__asm__ __volatile__(						\
22662306a36Sopenharmony_ci			"       rsil    a14,"__stringify(TOPLEVEL)"\n"	\
22762306a36Sopenharmony_ci			"       l32i    %[result], %[mem]\n"		\
22862306a36Sopenharmony_ci			"       " #op " %[tmp], %[result], %[i]\n"	\
22962306a36Sopenharmony_ci			"       s32i    %[tmp], %[mem]\n"		\
23062306a36Sopenharmony_ci			"       wsr     a14, ps\n"			\
23162306a36Sopenharmony_ci			"       rsync\n"				\
23262306a36Sopenharmony_ci			: [result] "=&a" (vval), [tmp] "=&a" (tmp),	\
23362306a36Sopenharmony_ci			  [mem] "+m" (*v)				\
23462306a36Sopenharmony_ci			: [i] "a" (i)					\
23562306a36Sopenharmony_ci			: "a14", "memory"				\
23662306a36Sopenharmony_ci			);						\
23762306a36Sopenharmony_ci									\
23862306a36Sopenharmony_ci	return vval;							\
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci#endif /* XCHAL_HAVE_S32C1I */
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) ATOMIC_OP_RETURN(op)
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ciATOMIC_OPS(add)
24662306a36Sopenharmony_ciATOMIC_OPS(sub)
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci#define arch_atomic_add_return			arch_atomic_add_return
24962306a36Sopenharmony_ci#define arch_atomic_sub_return			arch_atomic_sub_return
25062306a36Sopenharmony_ci#define arch_atomic_fetch_add			arch_atomic_fetch_add
25162306a36Sopenharmony_ci#define arch_atomic_fetch_sub			arch_atomic_fetch_sub
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci#undef ATOMIC_OPS
25462306a36Sopenharmony_ci#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ciATOMIC_OPS(and)
25762306a36Sopenharmony_ciATOMIC_OPS(or)
25862306a36Sopenharmony_ciATOMIC_OPS(xor)
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci#define arch_atomic_fetch_and			arch_atomic_fetch_and
26162306a36Sopenharmony_ci#define arch_atomic_fetch_or			arch_atomic_fetch_or
26262306a36Sopenharmony_ci#define arch_atomic_fetch_xor			arch_atomic_fetch_xor
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci#undef ATOMIC_OPS
26562306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP
26662306a36Sopenharmony_ci#undef ATOMIC_OP_RETURN
26762306a36Sopenharmony_ci#undef ATOMIC_OP
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci#endif /* _XTENSA_ATOMIC_H */
270