169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#ifndef __ARCH_M68K_ATOMIC__
269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#define __ARCH_M68K_ATOMIC__
369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#include <linux/types.h>
5803f69144f0d48863c68f9d111b56849c7cef5bbDavid Howells#include <linux/irqflags.h>
67224c0d1045327d637dab2c90777b6d5ec6d6804Greg Ungerer#include <asm/cmpxchg.h>
72db56e8606016e33903c64feaed989ffecd66a1bPeter Zijlstra#include <asm/barrier.h>
869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer/*
1069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer * Atomic operations that C can't guarantee us.  Useful for
1169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer * resource counting etc..
1269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer */
1369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
1469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer/*
1569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer * We do not have SMP m68k systems, so we don't have to deal with that.
1669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer */
1769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
1869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#define ATOMIC_INIT(i)	{ (i) }
1969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
202291059c852706c6f5ffb400366042b7625066cdPranith Kumar#define atomic_read(v)		ACCESS_ONCE((v)->counter)
2169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#define atomic_set(v, i)	(((v)->counter) = i)
2269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
2369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer/*
2469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer * The ColdFire parts cannot do some immediate to memory operations,
2569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer * so for them we do not specify the "i" asm constraint.
2669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer */
2769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#ifdef CONFIG_COLDFIRE
2869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#define	ASM_DI	"d"
2949148020bcb6910ce71417bd990a5ce7017f9bd3Sam Ravnborg#else
3069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#define	ASM_DI	"di"
3149148020bcb6910ce71417bd990a5ce7017f9bd3Sam Ravnborg#endif
32b417b717093085e45867770b29b9a97692cf132aGeert Uytterhoeven
33d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#define ATOMIC_OP(op, c_op, asm_op)					\
34d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstrastatic inline void atomic_##op(int i, atomic_t *v)			\
35d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra{									\
36d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	__asm__ __volatile__(#asm_op "l %1,%0" : "+m" (*v) : ASM_DI (i));\
37d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra}									\
38d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra
39d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#ifdef CONFIG_RMW_INSNS
40d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra
41d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#define ATOMIC_OP_RETURN(op, c_op, asm_op)				\
42d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstrastatic inline int atomic_##op##_return(int i, atomic_t *v)		\
43d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra{									\
44d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	int t, tmp;							\
45d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra									\
46d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	__asm__ __volatile__(						\
47d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra			"1:	movel %2,%1\n"				\
48d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra			"	" #asm_op "l %3,%1\n"			\
49d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra			"	casl %2,%1,%0\n"			\
50d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra			"	jne 1b"					\
51d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra			: "+m" (*v), "=&d" (t), "=&d" (tmp)		\
52d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra			: "g" (i), "2" (atomic_read(v)));		\
53d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	return t;							\
5469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
5569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
56d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#else
57d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra
58d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#define ATOMIC_OP_RETURN(op, c_op, asm_op)				\
59d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstrastatic inline int atomic_##op##_return(int i, atomic_t * v)		\
60d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra{									\
61d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	unsigned long flags;						\
62d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	int t;								\
63d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra									\
64d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	local_irq_save(flags);						\
65d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	t = (v->counter c_op i);					\
66d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	local_irq_restore(flags);					\
67d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra									\
68d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	return t;							\
6969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
7069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
71d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#endif /* CONFIG_RMW_INSNS */
72d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra
73d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#define ATOMIC_OPS(op, c_op, asm_op)					\
74d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	ATOMIC_OP(op, c_op, asm_op)					\
75d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra	ATOMIC_OP_RETURN(op, c_op, asm_op)
76d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra
77d839bae4269aea46bff4133066a411cfba5c7c46Peter ZijlstraATOMIC_OPS(add, +=, add)
78d839bae4269aea46bff4133066a411cfba5c7c46Peter ZijlstraATOMIC_OPS(sub, -=, sub)
79d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra
80d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#undef ATOMIC_OPS
81d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#undef ATOMIC_OP_RETURN
82d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra#undef ATOMIC_OP
83d839bae4269aea46bff4133066a411cfba5c7c46Peter Zijlstra
8469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline void atomic_inc(atomic_t *v)
8569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
8669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	__asm__ __volatile__("addql #1,%0" : "+m" (*v));
8769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
8869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
8969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline void atomic_dec(atomic_t *v)
9069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
9169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	__asm__ __volatile__("subql #1,%0" : "+m" (*v));
9269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
9369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
9469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline int atomic_dec_and_test(atomic_t *v)
9569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
9669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	char c;
9769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	__asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "+m" (*v));
9869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	return c != 0;
9969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
10069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
10183b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungererstatic inline int atomic_dec_and_test_lt(atomic_t *v)
10283b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungerer{
10383b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungerer	char c;
10483b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungerer	__asm__ __volatile__(
10583b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungerer		"subql #1,%1; slt %0"
10683b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungerer		: "=d" (c), "=m" (*v)
10783b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungerer		: "m" (*v));
10883b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungerer	return c != 0;
10983b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungerer}
11083b73d6cb8301df32d9887c16c83490c4fd1f55fGreg Ungerer
11169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline int atomic_inc_and_test(atomic_t *v)
11269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
11369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	char c;
11469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	__asm__ __volatile__("addql #1,%1; seq %0" : "=d" (c), "+m" (*v));
11569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	return c != 0;
11669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
11769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
11869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#ifdef CONFIG_RMW_INSNS
11969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
12069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
12169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
12269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
12369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#else /* !CONFIG_RMW_INSNS */
12469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
12569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline int atomic_cmpxchg(atomic_t *v, int old, int new)
12669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
12769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	unsigned long flags;
12869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	int prev;
12969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
13069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	local_irq_save(flags);
13169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	prev = atomic_read(v);
13269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	if (prev == old)
13369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer		atomic_set(v, new);
13469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	local_irq_restore(flags);
13569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	return prev;
13669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
13769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
13869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline int atomic_xchg(atomic_t *v, int new)
13969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
14069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	unsigned long flags;
14169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	int prev;
14269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
14369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	local_irq_save(flags);
14469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	prev = atomic_read(v);
14569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	atomic_set(v, new);
14669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	local_irq_restore(flags);
14769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	return prev;
14869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
14969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
15069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#endif /* !CONFIG_RMW_INSNS */
15169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
15269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#define atomic_dec_return(v)	atomic_sub_return(1, (v))
15369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#define atomic_inc_return(v)	atomic_add_return(1, (v))
15469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
15569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline int atomic_sub_and_test(int i, atomic_t *v)
15669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
15769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	char c;
15869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	__asm__ __volatile__("subl %2,%1; seq %0"
15969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer			     : "=d" (c), "+m" (*v)
16069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer			     : ASM_DI (i));
16169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	return c != 0;
16269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
16369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
16469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline int atomic_add_negative(int i, atomic_t *v)
16569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
16669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	char c;
16769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	__asm__ __volatile__("addl %2,%1; smi %0"
16869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer			     : "=d" (c), "+m" (*v)
16935de674982aa13de98cf470c640895164017563eGreg Ungerer			     : ASM_DI (i));
17069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	return c != 0;
17169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
17269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
17369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline void atomic_clear_mask(unsigned long mask, unsigned long *v)
17469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
17535de674982aa13de98cf470c640895164017563eGreg Ungerer	__asm__ __volatile__("andl %1,%0" : "+m" (*v) : ASM_DI (~(mask)));
17669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
17769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
17869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungererstatic inline void atomic_set_mask(unsigned long mask, unsigned long *v)
17969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
18035de674982aa13de98cf470c640895164017563eGreg Ungerer	__asm__ __volatile__("orl %1,%0" : "+m" (*v) : ASM_DI (mask));
18169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
18269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
183f24219b4e90cf70ec4a211b17fbabc725a0ddf3cArun Sharmastatic __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
18469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer{
18569f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	int c, old;
18669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	c = atomic_read(v);
18769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	for (;;) {
18869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer		if (unlikely(c == (u)))
18969f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer			break;
19069f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer		old = atomic_cmpxchg((v), c, c + (a));
19169f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer		if (likely(old == c))
19269f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer			break;
19369f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer		c = old;
19469f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer	}
195f24219b4e90cf70ec4a211b17fbabc725a0ddf3cArun Sharma	return c;
19669f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer}
19769f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer
19869f99746a2cfd88b9caed8e320ad86405b228adaGreg Ungerer#endif /* __ARCH_M68K_ATOMIC __ */
199