18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __ARCH_M68K_CMPXCHG__
38c2ecf20Sopenharmony_ci#define __ARCH_M68K_CMPXCHG__
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/irqflags.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_cistruct __xchg_dummy { unsigned long a[100]; };
88c2ecf20Sopenharmony_ci#define __xg(x) ((volatile struct __xchg_dummy *)(x))
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ciextern unsigned long __invalid_xchg_size(unsigned long, volatile void *, int);
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#ifndef CONFIG_RMW_INSNS
138c2ecf20Sopenharmony_cistatic inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	unsigned long flags, tmp;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	local_irq_save(flags);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	switch (size) {
208c2ecf20Sopenharmony_ci	case 1:
218c2ecf20Sopenharmony_ci		tmp = *(u8 *)ptr;
228c2ecf20Sopenharmony_ci		*(u8 *)ptr = x;
238c2ecf20Sopenharmony_ci		x = tmp;
248c2ecf20Sopenharmony_ci		break;
258c2ecf20Sopenharmony_ci	case 2:
268c2ecf20Sopenharmony_ci		tmp = *(u16 *)ptr;
278c2ecf20Sopenharmony_ci		*(u16 *)ptr = x;
288c2ecf20Sopenharmony_ci		x = tmp;
298c2ecf20Sopenharmony_ci		break;
308c2ecf20Sopenharmony_ci	case 4:
318c2ecf20Sopenharmony_ci		tmp = *(u32 *)ptr;
328c2ecf20Sopenharmony_ci		*(u32 *)ptr = x;
338c2ecf20Sopenharmony_ci		x = tmp;
348c2ecf20Sopenharmony_ci		break;
358c2ecf20Sopenharmony_ci	default:
368c2ecf20Sopenharmony_ci		tmp = __invalid_xchg_size(x, ptr, size);
378c2ecf20Sopenharmony_ci		break;
388c2ecf20Sopenharmony_ci	}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	local_irq_restore(flags);
418c2ecf20Sopenharmony_ci	return x;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci#else
448c2ecf20Sopenharmony_cistatic inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	switch (size) {
478c2ecf20Sopenharmony_ci	case 1:
488c2ecf20Sopenharmony_ci		__asm__ __volatile__
498c2ecf20Sopenharmony_ci			("moveb %2,%0\n\t"
508c2ecf20Sopenharmony_ci			 "1:\n\t"
518c2ecf20Sopenharmony_ci			 "casb %0,%1,%2\n\t"
528c2ecf20Sopenharmony_ci			 "jne 1b"
538c2ecf20Sopenharmony_ci			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
548c2ecf20Sopenharmony_ci		break;
558c2ecf20Sopenharmony_ci	case 2:
568c2ecf20Sopenharmony_ci		__asm__ __volatile__
578c2ecf20Sopenharmony_ci			("movew %2,%0\n\t"
588c2ecf20Sopenharmony_ci			 "1:\n\t"
598c2ecf20Sopenharmony_ci			 "casw %0,%1,%2\n\t"
608c2ecf20Sopenharmony_ci			 "jne 1b"
618c2ecf20Sopenharmony_ci			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
628c2ecf20Sopenharmony_ci		break;
638c2ecf20Sopenharmony_ci	case 4:
648c2ecf20Sopenharmony_ci		__asm__ __volatile__
658c2ecf20Sopenharmony_ci			("movel %2,%0\n\t"
668c2ecf20Sopenharmony_ci			 "1:\n\t"
678c2ecf20Sopenharmony_ci			 "casl %0,%1,%2\n\t"
688c2ecf20Sopenharmony_ci			 "jne 1b"
698c2ecf20Sopenharmony_ci			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
708c2ecf20Sopenharmony_ci		break;
718c2ecf20Sopenharmony_ci	default:
728c2ecf20Sopenharmony_ci		x = __invalid_xchg_size(x, ptr, size);
738c2ecf20Sopenharmony_ci		break;
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci	return x;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci#endif
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#include <asm-generic/cmpxchg-local.h>
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ciextern unsigned long __invalid_cmpxchg_size(volatile void *,
868c2ecf20Sopenharmony_ci					    unsigned long, unsigned long, int);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/*
898c2ecf20Sopenharmony_ci * Atomic compare and exchange.  Compare OLD with MEM, if identical,
908c2ecf20Sopenharmony_ci * store NEW in MEM.  Return the initial value in MEM.  Success is
918c2ecf20Sopenharmony_ci * indicated by comparing RETURN with OLD.
928c2ecf20Sopenharmony_ci */
938c2ecf20Sopenharmony_ci#ifdef CONFIG_RMW_INSNS
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
968c2ecf20Sopenharmony_ci				      unsigned long new, int size)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	switch (size) {
998c2ecf20Sopenharmony_ci	case 1:
1008c2ecf20Sopenharmony_ci		__asm__ __volatile__ ("casb %0,%2,%1"
1018c2ecf20Sopenharmony_ci				      : "=d" (old), "=m" (*(char *)p)
1028c2ecf20Sopenharmony_ci				      : "d" (new), "0" (old), "m" (*(char *)p));
1038c2ecf20Sopenharmony_ci		break;
1048c2ecf20Sopenharmony_ci	case 2:
1058c2ecf20Sopenharmony_ci		__asm__ __volatile__ ("casw %0,%2,%1"
1068c2ecf20Sopenharmony_ci				      : "=d" (old), "=m" (*(short *)p)
1078c2ecf20Sopenharmony_ci				      : "d" (new), "0" (old), "m" (*(short *)p));
1088c2ecf20Sopenharmony_ci		break;
1098c2ecf20Sopenharmony_ci	case 4:
1108c2ecf20Sopenharmony_ci		__asm__ __volatile__ ("casl %0,%2,%1"
1118c2ecf20Sopenharmony_ci				      : "=d" (old), "=m" (*(int *)p)
1128c2ecf20Sopenharmony_ci				      : "d" (new), "0" (old), "m" (*(int *)p));
1138c2ecf20Sopenharmony_ci		break;
1148c2ecf20Sopenharmony_ci	default:
1158c2ecf20Sopenharmony_ci		old = __invalid_cmpxchg_size(p, old, new, size);
1168c2ecf20Sopenharmony_ci		break;
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci	return old;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#define cmpxchg(ptr, o, n)						    \
1228c2ecf20Sopenharmony_ci	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),	    \
1238c2ecf20Sopenharmony_ci			(unsigned long)(n), sizeof(*(ptr))))
1248c2ecf20Sopenharmony_ci#define cmpxchg_local(ptr, o, n)					    \
1258c2ecf20Sopenharmony_ci	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),	    \
1268c2ecf20Sopenharmony_ci			(unsigned long)(n), sizeof(*(ptr))))
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci#define cmpxchg64(ptr, o, n)	cmpxchg64_local((ptr), (o), (n))
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci#else
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#include <asm-generic/cmpxchg.h>
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci#endif
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci#endif /* __ARCH_M68K_CMPXCHG__ */
137