cmpxchg-local.h 1.3 KB

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