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