cmpxchg.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef __ARCH_M68K_CMPXCHG__
  3. #define __ARCH_M68K_CMPXCHG__
  4. #include <linux/irqflags.h>
  5. struct __xchg_dummy { unsigned long a[100]; };
  6. #define __xg(x) ((volatile struct __xchg_dummy *)(x))
  7. extern unsigned long __invalid_xchg_size(unsigned long, volatile void *, int);
  8. #ifndef CONFIG_RMW_INSNS
  9. static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
  10. {
  11. unsigned long flags, tmp;
  12. local_irq_save(flags);
  13. switch (size) {
  14. case 1:
  15. tmp = *(u8 *)ptr;
  16. *(u8 *)ptr = x;
  17. x = tmp;
  18. break;
  19. case 2:
  20. tmp = *(u16 *)ptr;
  21. *(u16 *)ptr = x;
  22. x = tmp;
  23. break;
  24. case 4:
  25. tmp = *(u32 *)ptr;
  26. *(u32 *)ptr = x;
  27. x = tmp;
  28. break;
  29. default:
  30. tmp = __invalid_xchg_size(x, ptr, size);
  31. break;
  32. }
  33. local_irq_restore(flags);
  34. return x;
  35. }
  36. #else
  37. static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
  38. {
  39. switch (size) {
  40. case 1:
  41. __asm__ __volatile__
  42. ("moveb %2,%0\n\t"
  43. "1:\n\t"
  44. "casb %0,%1,%2\n\t"
  45. "jne 1b"
  46. : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
  47. break;
  48. case 2:
  49. __asm__ __volatile__
  50. ("movew %2,%0\n\t"
  51. "1:\n\t"
  52. "casw %0,%1,%2\n\t"
  53. "jne 1b"
  54. : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
  55. break;
  56. case 4:
  57. __asm__ __volatile__
  58. ("movel %2,%0\n\t"
  59. "1:\n\t"
  60. "casl %0,%1,%2\n\t"
  61. "jne 1b"
  62. : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
  63. break;
  64. default:
  65. x = __invalid_xchg_size(x, ptr, size);
  66. break;
  67. }
  68. return x;
  69. }
  70. #endif
  71. #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
  72. #include <asm-generic/cmpxchg-local.h>
  73. #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
  74. extern unsigned long __invalid_cmpxchg_size(volatile void *,
  75. unsigned long, unsigned long, int);
  76. /*
  77. * Atomic compare and exchange. Compare OLD with MEM, if identical,
  78. * store NEW in MEM. Return the initial value in MEM. Success is
  79. * indicated by comparing RETURN with OLD.
  80. */
  81. #ifdef CONFIG_RMW_INSNS
  82. static inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
  83. unsigned long new, int size)
  84. {
  85. switch (size) {
  86. case 1:
  87. __asm__ __volatile__ ("casb %0,%2,%1"
  88. : "=d" (old), "=m" (*(char *)p)
  89. : "d" (new), "0" (old), "m" (*(char *)p));
  90. break;
  91. case 2:
  92. __asm__ __volatile__ ("casw %0,%2,%1"
  93. : "=d" (old), "=m" (*(short *)p)
  94. : "d" (new), "0" (old), "m" (*(short *)p));
  95. break;
  96. case 4:
  97. __asm__ __volatile__ ("casl %0,%2,%1"
  98. : "=d" (old), "=m" (*(int *)p)
  99. : "d" (new), "0" (old), "m" (*(int *)p));
  100. break;
  101. default:
  102. old = __invalid_cmpxchg_size(p, old, new, size);
  103. break;
  104. }
  105. return old;
  106. }
  107. #define cmpxchg(ptr, o, n) \
  108. ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
  109. (unsigned long)(n), sizeof(*(ptr))))
  110. #define cmpxchg_local(ptr, o, n) \
  111. ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
  112. (unsigned long)(n), sizeof(*(ptr))))
  113. #define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n))
  114. #else
  115. /*
  116. * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
  117. * them available.
  118. */
  119. #define cmpxchg_local(ptr, o, n) \
  120. ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
  121. (unsigned long)(n), sizeof(*(ptr))))
  122. #include <asm-generic/cmpxchg.h>
  123. #endif
  124. #endif /* __ARCH_M68K_CMPXCHG__ */