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