cmpxchg-local.h 1.4 KB

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