1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Generic UP xchg and cmpxchg using interrupt disablement. Does not 4 * support SMP. 5 */ 6 7 #ifndef __ASM_GENERIC_CMPXCHG_H 8 #define __ASM_GENERIC_CMPXCHG_H 9 10 #ifdef CONFIG_SMP 11 #error "Cannot use generic cmpxchg on SMP" 12 #endif 13 14 #include <linux/types.h> 15 #include <linux/irqflags.h> 16 17 #ifndef xchg 18 19 /* 20 * This function doesn't exist, so you'll get a linker error if 21 * something tries to do an invalidly-sized xchg(). 22 */ 23 extern void __xchg_called_with_bad_pointer(void); 24 25 static inline 26 unsigned long __xchg(unsigned long x, volatile void *ptr, int size) 27 { 28 unsigned long ret, flags; 29 30 switch (size) { 31 case 1: 32 #ifdef __xchg_u8 33 return __xchg_u8(x, ptr); 34 #else 35 local_irq_save(flags); 36 ret = *(volatile u8 *)ptr; 37 *(volatile u8 *)ptr = x; 38 local_irq_restore(flags); 39 return ret; 40 #endif /* __xchg_u8 */ 41 42 case 2: 43 #ifdef __xchg_u16 44 return __xchg_u16(x, ptr); 45 #else 46 local_irq_save(flags); 47 ret = *(volatile u16 *)ptr; 48 *(volatile u16 *)ptr = x; 49 local_irq_restore(flags); 50 return ret; 51 #endif /* __xchg_u16 */ 52 53 case 4: 54 #ifdef __xchg_u32 55 return __xchg_u32(x, ptr); 56 #else 57 local_irq_save(flags); 58 ret = *(volatile u32 *)ptr; 59 *(volatile u32 *)ptr = x; 60 local_irq_restore(flags); 61 return ret; 62 #endif /* __xchg_u32 */ 63 64 #ifdef CONFIG_64BIT 65 case 8: 66 #ifdef __xchg_u64 67 return __xchg_u64(x, ptr); 68 #else 69 local_irq_save(flags); 70 ret = *(volatile u64 *)ptr; 71 *(volatile u64 *)ptr = x; 72 local_irq_restore(flags); 73 return ret; 74 #endif /* __xchg_u64 */ 75 #endif /* CONFIG_64BIT */ 76 77 default: 78 __xchg_called_with_bad_pointer(); 79 return x; 80 } 81 } 82 83 #define xchg(ptr, x) ({ \ 84 ((__typeof__(*(ptr))) \ 85 __xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))); \ 86 }) 87 88 #endif /* xchg */ 89 90 /* 91 * Atomic compare and exchange. 92 */ 93 #include <asm-generic/cmpxchg-local.h> 94 95 #ifndef cmpxchg_local 96 #define cmpxchg_local(ptr, o, n) ({ \ 97 ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ 98 (unsigned long)(n), sizeof(*(ptr)))); \ 99 }) 100 #endif 101 102 #ifndef cmpxchg64_local 103 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) 104 #endif 105 106 #define cmpxchg(ptr, o, n) cmpxchg_local((ptr), (o), (n)) 107 #define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n)) 108 109 #endif /* __ASM_GENERIC_CMPXCHG_H */ 110