1 #ifndef __ASM_GENERIC_CMPXCHG_LOCAL_H 2 #define __ASM_GENERIC_CMPXCHG_LOCAL_H 3 4 #include <linux/types.h> 5 #include <linux/irqflags.h> 6 7 extern unsigned long wrong_size_cmpxchg(volatile void *ptr) 8 __noreturn; 9 10 /* 11 * Generic version of __cmpxchg_local (disables interrupts). Takes an unsigned 12 * long parameter, supporting various types of architectures. 13 */ 14 static inline unsigned long __cmpxchg_local_generic(volatile void *ptr, 15 unsigned long old, unsigned long new, int size) 16 { 17 unsigned long flags, prev; 18 19 /* 20 * Sanity checking, compile-time. 21 */ 22 if (size == 8 && sizeof(unsigned long) != 8) 23 wrong_size_cmpxchg(ptr); 24 25 raw_local_irq_save(flags); 26 switch (size) { 27 case 1: prev = *(u8 *)ptr; 28 if (prev == old) 29 *(u8 *)ptr = (u8)new; 30 break; 31 case 2: prev = *(u16 *)ptr; 32 if (prev == old) 33 *(u16 *)ptr = (u16)new; 34 break; 35 case 4: prev = *(u32 *)ptr; 36 if (prev == old) 37 *(u32 *)ptr = (u32)new; 38 break; 39 case 8: prev = *(u64 *)ptr; 40 if (prev == old) 41 *(u64 *)ptr = (u64)new; 42 break; 43 default: 44 wrong_size_cmpxchg(ptr); 45 } 46 raw_local_irq_restore(flags); 47 return prev; 48 } 49 50 /* 51 * Generic version of __cmpxchg64_local. Takes an u64 parameter. 52 */ 53 static inline u64 __cmpxchg64_local_generic(volatile void *ptr, 54 u64 old, u64 new) 55 { 56 u64 prev; 57 unsigned long flags; 58 59 raw_local_irq_save(flags); 60 prev = *(u64 *)ptr; 61 if (prev == old) 62 *(u64 *)ptr = new; 63 raw_local_irq_restore(flags); 64 return prev; 65 } 66 67 #endif 68