cmpxchg-local.h 1.4 KB

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