0001
0002 #ifndef __ASM_GENERIC_CMPXCHG_LOCAL_H
0003 #define __ASM_GENERIC_CMPXCHG_LOCAL_H
0004
0005 #include <linux/types.h>
0006 #include <linux/irqflags.h>
0007
0008 extern unsigned long wrong_size_cmpxchg(volatile void *ptr)
0009 __noreturn;
0010
0011
0012
0013
0014
0015 static inline unsigned long __generic_cmpxchg_local(volatile void *ptr,
0016 unsigned long old, unsigned long new, int size)
0017 {
0018 unsigned long flags, prev;
0019
0020
0021
0022
0023 if (size == 8 && sizeof(unsigned long) != 8)
0024 wrong_size_cmpxchg(ptr);
0025
0026 raw_local_irq_save(flags);
0027 switch (size) {
0028 case 1: prev = *(u8 *)ptr;
0029 if (prev == old)
0030 *(u8 *)ptr = (u8)new;
0031 break;
0032 case 2: prev = *(u16 *)ptr;
0033 if (prev == old)
0034 *(u16 *)ptr = (u16)new;
0035 break;
0036 case 4: prev = *(u32 *)ptr;
0037 if (prev == old)
0038 *(u32 *)ptr = (u32)new;
0039 break;
0040 case 8: prev = *(u64 *)ptr;
0041 if (prev == old)
0042 *(u64 *)ptr = (u64)new;
0043 break;
0044 default:
0045 wrong_size_cmpxchg(ptr);
0046 }
0047 raw_local_irq_restore(flags);
0048 return prev;
0049 }
0050
0051
0052
0053
0054 static inline u64 __generic_cmpxchg64_local(volatile void *ptr,
0055 u64 old, u64 new)
0056 {
0057 u64 prev;
0058 unsigned long flags;
0059
0060 raw_local_irq_save(flags);
0061 prev = *(u64 *)ptr;
0062 if (prev == old)
0063 *(u64 *)ptr = new;
0064 raw_local_irq_restore(flags);
0065 return prev;
0066 }
0067
0068 #endif