1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2803f6914SDavid Howells #ifndef __ARCH_M68K_CMPXCHG__
3803f6914SDavid Howells #define __ARCH_M68K_CMPXCHG__
4803f6914SDavid Howells
5803f6914SDavid Howells #include <linux/irqflags.h>
6803f6914SDavid Howells
72a55550fSKees Cook #define __xg(type, x) ((volatile type *)(x))
8803f6914SDavid Howells
9803f6914SDavid Howells extern unsigned long __invalid_xchg_size(unsigned long, volatile void *, int);
10803f6914SDavid Howells
11803f6914SDavid Howells #ifndef CONFIG_RMW_INSNS
__arch_xchg(unsigned long x,volatile void * ptr,int size)1206855063SAndrzej Hajda static inline unsigned long __arch_xchg(unsigned long x, volatile void * ptr, int size)
13803f6914SDavid Howells {
14803f6914SDavid Howells unsigned long flags, tmp;
15803f6914SDavid Howells
16803f6914SDavid Howells local_irq_save(flags);
17803f6914SDavid Howells
18803f6914SDavid Howells switch (size) {
19803f6914SDavid Howells case 1:
20803f6914SDavid Howells tmp = *(u8 *)ptr;
21803f6914SDavid Howells *(u8 *)ptr = x;
22803f6914SDavid Howells x = tmp;
23803f6914SDavid Howells break;
24803f6914SDavid Howells case 2:
25803f6914SDavid Howells tmp = *(u16 *)ptr;
26803f6914SDavid Howells *(u16 *)ptr = x;
27803f6914SDavid Howells x = tmp;
28803f6914SDavid Howells break;
29803f6914SDavid Howells case 4:
30803f6914SDavid Howells tmp = *(u32 *)ptr;
31803f6914SDavid Howells *(u32 *)ptr = x;
32803f6914SDavid Howells x = tmp;
33803f6914SDavid Howells break;
34803f6914SDavid Howells default:
35*b8cdefdaSThorsten Blum x = __invalid_xchg_size(x, ptr, size);
36803f6914SDavid Howells break;
37803f6914SDavid Howells }
38803f6914SDavid Howells
39803f6914SDavid Howells local_irq_restore(flags);
40803f6914SDavid Howells return x;
41803f6914SDavid Howells }
42803f6914SDavid Howells #else
__arch_xchg(unsigned long x,volatile void * ptr,int size)4306855063SAndrzej Hajda static inline unsigned long __arch_xchg(unsigned long x, volatile void * ptr, int size)
44803f6914SDavid Howells {
45803f6914SDavid Howells switch (size) {
46803f6914SDavid Howells case 1:
47803f6914SDavid Howells __asm__ __volatile__
48803f6914SDavid Howells ("moveb %2,%0\n\t"
49803f6914SDavid Howells "1:\n\t"
50803f6914SDavid Howells "casb %0,%1,%2\n\t"
51803f6914SDavid Howells "jne 1b"
522a55550fSKees Cook : "=&d" (x) : "d" (x), "m" (*__xg(u8, ptr)) : "memory");
53803f6914SDavid Howells break;
54803f6914SDavid Howells case 2:
55803f6914SDavid Howells __asm__ __volatile__
56803f6914SDavid Howells ("movew %2,%0\n\t"
57803f6914SDavid Howells "1:\n\t"
58803f6914SDavid Howells "casw %0,%1,%2\n\t"
59803f6914SDavid Howells "jne 1b"
602a55550fSKees Cook : "=&d" (x) : "d" (x), "m" (*__xg(u16, ptr)) : "memory");
61803f6914SDavid Howells break;
62803f6914SDavid Howells case 4:
63803f6914SDavid Howells __asm__ __volatile__
64803f6914SDavid Howells ("movel %2,%0\n\t"
65803f6914SDavid Howells "1:\n\t"
66803f6914SDavid Howells "casl %0,%1,%2\n\t"
67803f6914SDavid Howells "jne 1b"
682a55550fSKees Cook : "=&d" (x) : "d" (x), "m" (*__xg(u32, ptr)) : "memory");
69803f6914SDavid Howells break;
70803f6914SDavid Howells default:
71803f6914SDavid Howells x = __invalid_xchg_size(x, ptr, size);
72803f6914SDavid Howells break;
73803f6914SDavid Howells }
74803f6914SDavid Howells return x;
75803f6914SDavid Howells }
76803f6914SDavid Howells #endif
77803f6914SDavid Howells
7806855063SAndrzej Hajda #define arch_xchg(ptr,x) ({(__typeof__(*(ptr)))__arch_xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));})
79803f6914SDavid Howells
80803f6914SDavid Howells #include <asm-generic/cmpxchg-local.h>
81803f6914SDavid Howells
82e86e793cSMark Rutland #define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
83803f6914SDavid Howells
84803f6914SDavid Howells extern unsigned long __invalid_cmpxchg_size(volatile void *,
85803f6914SDavid Howells unsigned long, unsigned long, int);
86803f6914SDavid Howells
87803f6914SDavid Howells /*
88803f6914SDavid Howells * Atomic compare and exchange. Compare OLD with MEM, if identical,
89803f6914SDavid Howells * store NEW in MEM. Return the initial value in MEM. Success is
90803f6914SDavid Howells * indicated by comparing RETURN with OLD.
91803f6914SDavid Howells */
92803f6914SDavid Howells #ifdef CONFIG_RMW_INSNS
93803f6914SDavid Howells
__cmpxchg(volatile void * p,unsigned long old,unsigned long new,int size)94803f6914SDavid Howells static inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
95803f6914SDavid Howells unsigned long new, int size)
96803f6914SDavid Howells {
97803f6914SDavid Howells switch (size) {
98803f6914SDavid Howells case 1:
99803f6914SDavid Howells __asm__ __volatile__ ("casb %0,%2,%1"
100803f6914SDavid Howells : "=d" (old), "=m" (*(char *)p)
101803f6914SDavid Howells : "d" (new), "0" (old), "m" (*(char *)p));
102803f6914SDavid Howells break;
103803f6914SDavid Howells case 2:
104803f6914SDavid Howells __asm__ __volatile__ ("casw %0,%2,%1"
105803f6914SDavid Howells : "=d" (old), "=m" (*(short *)p)
106803f6914SDavid Howells : "d" (new), "0" (old), "m" (*(short *)p));
107803f6914SDavid Howells break;
108803f6914SDavid Howells case 4:
109803f6914SDavid Howells __asm__ __volatile__ ("casl %0,%2,%1"
110803f6914SDavid Howells : "=d" (old), "=m" (*(int *)p)
111803f6914SDavid Howells : "d" (new), "0" (old), "m" (*(int *)p));
112803f6914SDavid Howells break;
113803f6914SDavid Howells default:
114803f6914SDavid Howells old = __invalid_cmpxchg_size(p, old, new, size);
115803f6914SDavid Howells break;
116803f6914SDavid Howells }
117803f6914SDavid Howells return old;
118803f6914SDavid Howells }
119803f6914SDavid Howells
120e86e793cSMark Rutland #define arch_cmpxchg(ptr, o, n) \
1211e10cf44SArnd Bergmann ({(__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
1221e10cf44SArnd Bergmann (unsigned long)(n), sizeof(*(ptr)));})
123e86e793cSMark Rutland #define arch_cmpxchg_local(ptr, o, n) \
1241e10cf44SArnd Bergmann ({(__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
1251e10cf44SArnd Bergmann (unsigned long)(n), sizeof(*(ptr)));})
126feb20ec2SGeert Uytterhoeven
127e86e793cSMark Rutland #define arch_cmpxchg64(ptr, o, n) arch_cmpxchg64_local((ptr), (o), (n))
128feb20ec2SGeert Uytterhoeven
129803f6914SDavid Howells #else
130803f6914SDavid Howells
131803f6914SDavid Howells #include <asm-generic/cmpxchg.h>
132803f6914SDavid Howells
133803f6914SDavid Howells #endif
134803f6914SDavid Howells
135803f6914SDavid Howells #endif /* __ARCH_M68K_CMPXCHG__ */
136