1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __ASM_SH_CMPXCHG_H 3 #define __ASM_SH_CMPXCHG_H 4 5 /* 6 * Atomic operations that C can't guarantee us. Useful for 7 * resource counting etc.. 8 */ 9 10 #include <linux/compiler.h> 11 #include <linux/types.h> 12 #include <linux/cmpxchg-emu.h> 13 14 #if defined(CONFIG_GUSA_RB) 15 #include <asm/cmpxchg-grb.h> 16 #elif defined(CONFIG_CPU_SH4A) 17 #include <asm/cmpxchg-llsc.h> 18 #elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP) 19 #include <asm/cmpxchg-cas.h> 20 #else 21 #include <asm/cmpxchg-irq.h> 22 #endif 23 24 extern void __xchg_called_with_bad_pointer(void); 25 26 #define __arch_xchg(ptr, x, size) \ 27 ({ \ 28 unsigned long __xchg__res; \ 29 volatile void *__xchg_ptr = (ptr); \ 30 switch (size) { \ 31 case 4: \ 32 __xchg__res = xchg_u32(__xchg_ptr, x); \ 33 break; \ 34 case 2: \ 35 __xchg__res = xchg_u16(__xchg_ptr, x); \ 36 break; \ 37 case 1: \ 38 __xchg__res = xchg_u8(__xchg_ptr, x); \ 39 break; \ 40 default: \ 41 __xchg_called_with_bad_pointer(); \ 42 __xchg__res = x; \ 43 break; \ 44 } \ 45 \ 46 __xchg__res; \ 47 }) 48 49 #define arch_xchg(ptr,x) \ 50 ((__typeof__(*(ptr)))__arch_xchg((ptr),(unsigned long)(x), sizeof(*(ptr)))) 51 52 /* This function doesn't exist, so you'll get a linker error 53 * if something tries to do an invalid cmpxchg(). */ 54 extern void __cmpxchg_called_with_bad_pointer(void); 55 56 static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old, 57 unsigned long new, int size) 58 { 59 switch (size) { 60 case 1: 61 return cmpxchg_emu_u8(ptr, old, new); 62 case 4: 63 return __cmpxchg_u32(ptr, old, new); 64 } 65 __cmpxchg_called_with_bad_pointer(); 66 return old; 67 } 68 69 #define arch_cmpxchg(ptr,o,n) \ 70 ({ \ 71 __typeof__(*(ptr)) _o_ = (o); \ 72 __typeof__(*(ptr)) _n_ = (n); \ 73 (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ 74 (unsigned long)_n_, sizeof(*(ptr))); \ 75 }) 76 77 #include <asm-generic/cmpxchg-local.h> 78 79 #define arch_cmpxchg_local(ptr, o, n) ({ \ 80 (__typeof__(*ptr))__generic_cmpxchg_local((ptr), \ 81 (unsigned long)(o), \ 82 (unsigned long)(n), \ 83 sizeof(*(ptr))); \ 84 }) 85 86 #endif /* __ASM_SH_CMPXCHG_H */ 87