18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __ARCH_M68K_ATOMIC__
38c2ecf20Sopenharmony_ci#define __ARCH_M68K_ATOMIC__
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/types.h>
68c2ecf20Sopenharmony_ci#include <linux/irqflags.h>
78c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h>
88c2ecf20Sopenharmony_ci#include <asm/barrier.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/*
118c2ecf20Sopenharmony_ci * Atomic operations that C can't guarantee us.  Useful for
128c2ecf20Sopenharmony_ci * resource counting etc..
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/*
168c2ecf20Sopenharmony_ci * We do not have SMP m68k systems, so we don't have to deal with that.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define atomic_read(v)		READ_ONCE((v)->counter)
208c2ecf20Sopenharmony_ci#define atomic_set(v, i)	WRITE_ONCE(((v)->counter), (i))
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * The ColdFire parts cannot do some immediate to memory operations,
248c2ecf20Sopenharmony_ci * so for them we do not specify the "i" asm constraint.
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci#ifdef CONFIG_COLDFIRE
278c2ecf20Sopenharmony_ci#define	ASM_DI	"d"
288c2ecf20Sopenharmony_ci#else
298c2ecf20Sopenharmony_ci#define	ASM_DI	"di"
308c2ecf20Sopenharmony_ci#endif
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, c_op, asm_op)					\
338c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v)			\
348c2ecf20Sopenharmony_ci{									\
358c2ecf20Sopenharmony_ci	__asm__ __volatile__(#asm_op "l %1,%0" : "+m" (*v) : ASM_DI (i));\
368c2ecf20Sopenharmony_ci}									\
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#ifdef CONFIG_RMW_INSNS
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op, c_op, asm_op)				\
418c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t *v)		\
428c2ecf20Sopenharmony_ci{									\
438c2ecf20Sopenharmony_ci	int t, tmp;							\
448c2ecf20Sopenharmony_ci									\
458c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
468c2ecf20Sopenharmony_ci			"1:	movel %2,%1\n"				\
478c2ecf20Sopenharmony_ci			"	" #asm_op "l %3,%1\n"			\
488c2ecf20Sopenharmony_ci			"	casl %2,%1,%0\n"			\
498c2ecf20Sopenharmony_ci			"	jne 1b"					\
508c2ecf20Sopenharmony_ci			: "+m" (*v), "=&d" (t), "=&d" (tmp)		\
518c2ecf20Sopenharmony_ci			: "g" (i), "2" (atomic_read(v)));		\
528c2ecf20Sopenharmony_ci	return t;							\
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, c_op, asm_op)				\
568c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t *v)			\
578c2ecf20Sopenharmony_ci{									\
588c2ecf20Sopenharmony_ci	int t, tmp;							\
598c2ecf20Sopenharmony_ci									\
608c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
618c2ecf20Sopenharmony_ci			"1:	movel %2,%1\n"				\
628c2ecf20Sopenharmony_ci			"	" #asm_op "l %3,%1\n"			\
638c2ecf20Sopenharmony_ci			"	casl %2,%1,%0\n"			\
648c2ecf20Sopenharmony_ci			"	jne 1b"					\
658c2ecf20Sopenharmony_ci			: "+m" (*v), "=&d" (t), "=&d" (tmp)		\
668c2ecf20Sopenharmony_ci			: "g" (i), "2" (atomic_read(v)));		\
678c2ecf20Sopenharmony_ci	return tmp;							\
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#else
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op, c_op, asm_op)				\
738c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t * v)		\
748c2ecf20Sopenharmony_ci{									\
758c2ecf20Sopenharmony_ci	unsigned long flags;						\
768c2ecf20Sopenharmony_ci	int t;								\
778c2ecf20Sopenharmony_ci									\
788c2ecf20Sopenharmony_ci	local_irq_save(flags);						\
798c2ecf20Sopenharmony_ci	t = (v->counter c_op i);					\
808c2ecf20Sopenharmony_ci	local_irq_restore(flags);					\
818c2ecf20Sopenharmony_ci									\
828c2ecf20Sopenharmony_ci	return t;							\
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, c_op, asm_op)				\
868c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t * v)		\
878c2ecf20Sopenharmony_ci{									\
888c2ecf20Sopenharmony_ci	unsigned long flags;						\
898c2ecf20Sopenharmony_ci	int t;								\
908c2ecf20Sopenharmony_ci									\
918c2ecf20Sopenharmony_ci	local_irq_save(flags);						\
928c2ecf20Sopenharmony_ci	t = v->counter;							\
938c2ecf20Sopenharmony_ci	v->counter c_op i;						\
948c2ecf20Sopenharmony_ci	local_irq_restore(flags);					\
958c2ecf20Sopenharmony_ci									\
968c2ecf20Sopenharmony_ci	return t;							\
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci#endif /* CONFIG_RMW_INSNS */
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, c_op, asm_op)					\
1028c2ecf20Sopenharmony_ci	ATOMIC_OP(op, c_op, asm_op)					\
1038c2ecf20Sopenharmony_ci	ATOMIC_OP_RETURN(op, c_op, asm_op)				\
1048c2ecf20Sopenharmony_ci	ATOMIC_FETCH_OP(op, c_op, asm_op)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciATOMIC_OPS(add, +=, add)
1078c2ecf20Sopenharmony_ciATOMIC_OPS(sub, -=, sub)
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#undef ATOMIC_OPS
1108c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, c_op, asm_op)					\
1118c2ecf20Sopenharmony_ci	ATOMIC_OP(op, c_op, asm_op)					\
1128c2ecf20Sopenharmony_ci	ATOMIC_FETCH_OP(op, c_op, asm_op)
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ciATOMIC_OPS(and, &=, and)
1158c2ecf20Sopenharmony_ciATOMIC_OPS(or, |=, or)
1168c2ecf20Sopenharmony_ciATOMIC_OPS(xor, ^=, eor)
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#undef ATOMIC_OPS
1198c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP
1208c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN
1218c2ecf20Sopenharmony_ci#undef ATOMIC_OP
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic inline void atomic_inc(atomic_t *v)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	__asm__ __volatile__("addql #1,%0" : "+m" (*v));
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci#define atomic_inc atomic_inc
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic inline void atomic_dec(atomic_t *v)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	__asm__ __volatile__("subql #1,%0" : "+m" (*v));
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci#define atomic_dec atomic_dec
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic inline int atomic_dec_and_test(atomic_t *v)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	char c;
1388c2ecf20Sopenharmony_ci	__asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "+m" (*v));
1398c2ecf20Sopenharmony_ci	return c != 0;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci#define atomic_dec_and_test atomic_dec_and_test
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic inline int atomic_dec_and_test_lt(atomic_t *v)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	char c;
1468c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1478c2ecf20Sopenharmony_ci		"subql #1,%1; slt %0"
1488c2ecf20Sopenharmony_ci		: "=d" (c), "=m" (*v)
1498c2ecf20Sopenharmony_ci		: "m" (*v));
1508c2ecf20Sopenharmony_ci	return c != 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic inline int atomic_inc_and_test(atomic_t *v)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	char c;
1568c2ecf20Sopenharmony_ci	__asm__ __volatile__("addql #1,%1; seq %0" : "=d" (c), "+m" (*v));
1578c2ecf20Sopenharmony_ci	return c != 0;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci#define atomic_inc_and_test atomic_inc_and_test
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci#ifdef CONFIG_RMW_INSNS
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
1648c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci#else /* !CONFIG_RMW_INSNS */
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic inline int atomic_cmpxchg(atomic_t *v, int old, int new)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	unsigned long flags;
1718c2ecf20Sopenharmony_ci	int prev;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	local_irq_save(flags);
1748c2ecf20Sopenharmony_ci	prev = atomic_read(v);
1758c2ecf20Sopenharmony_ci	if (prev == old)
1768c2ecf20Sopenharmony_ci		atomic_set(v, new);
1778c2ecf20Sopenharmony_ci	local_irq_restore(flags);
1788c2ecf20Sopenharmony_ci	return prev;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic inline int atomic_xchg(atomic_t *v, int new)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	unsigned long flags;
1848c2ecf20Sopenharmony_ci	int prev;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	local_irq_save(flags);
1878c2ecf20Sopenharmony_ci	prev = atomic_read(v);
1888c2ecf20Sopenharmony_ci	atomic_set(v, new);
1898c2ecf20Sopenharmony_ci	local_irq_restore(flags);
1908c2ecf20Sopenharmony_ci	return prev;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci#endif /* !CONFIG_RMW_INSNS */
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic inline int atomic_sub_and_test(int i, atomic_t *v)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	char c;
1988c2ecf20Sopenharmony_ci	__asm__ __volatile__("subl %2,%1; seq %0"
1998c2ecf20Sopenharmony_ci			     : "=d" (c), "+m" (*v)
2008c2ecf20Sopenharmony_ci			     : ASM_DI (i));
2018c2ecf20Sopenharmony_ci	return c != 0;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci#define atomic_sub_and_test atomic_sub_and_test
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic inline int atomic_add_negative(int i, atomic_t *v)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	char c;
2088c2ecf20Sopenharmony_ci	__asm__ __volatile__("addl %2,%1; smi %0"
2098c2ecf20Sopenharmony_ci			     : "=d" (c), "+m" (*v)
2108c2ecf20Sopenharmony_ci			     : ASM_DI (i));
2118c2ecf20Sopenharmony_ci	return c != 0;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci#define atomic_add_negative atomic_add_negative
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci#endif /* __ARCH_M68K_ATOMIC __ */
216