local.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ARCH_POWERPC_LOCAL_H
  3. #define _ARCH_POWERPC_LOCAL_H
  4. #ifdef CONFIG_PPC_BOOK3S_64
  5. #include <linux/percpu.h>
  6. #include <linux/atomic.h>
  7. #include <linux/irqflags.h>
  8. #include <asm/hw_irq.h>
  9. typedef struct
  10. {
  11. long v;
  12. } local_t;
  13. #define LOCAL_INIT(i) { (i) }
  14. static __inline__ long local_read(const local_t *l)
  15. {
  16. return READ_ONCE(l->v);
  17. }
  18. static __inline__ void local_set(local_t *l, long i)
  19. {
  20. WRITE_ONCE(l->v, i);
  21. }
  22. #define LOCAL_OP(op, c_op) \
  23. static __inline__ void local_##op(long i, local_t *l) \
  24. { \
  25. unsigned long flags; \
  26. \
  27. powerpc_local_irq_pmu_save(flags); \
  28. l->v c_op i; \
  29. powerpc_local_irq_pmu_restore(flags); \
  30. }
  31. #define LOCAL_OP_RETURN(op, c_op) \
  32. static __inline__ long local_##op##_return(long a, local_t *l) \
  33. { \
  34. long t; \
  35. unsigned long flags; \
  36. \
  37. powerpc_local_irq_pmu_save(flags); \
  38. t = (l->v c_op a); \
  39. powerpc_local_irq_pmu_restore(flags); \
  40. \
  41. return t; \
  42. }
  43. #define LOCAL_OPS(op, c_op) \
  44. LOCAL_OP(op, c_op) \
  45. LOCAL_OP_RETURN(op, c_op)
  46. LOCAL_OPS(add, +=)
  47. LOCAL_OPS(sub, -=)
  48. #define local_add_negative(a, l) (local_add_return((a), (l)) < 0)
  49. #define local_inc_return(l) local_add_return(1LL, l)
  50. #define local_inc(l) local_inc_return(l)
  51. /*
  52. * local_inc_and_test - increment and test
  53. * @l: pointer of type local_t
  54. *
  55. * Atomically increments @l by 1
  56. * and returns true if the result is zero, or false for all
  57. * other cases.
  58. */
  59. #define local_inc_and_test(l) (local_inc_return(l) == 0)
  60. #define local_dec_return(l) local_sub_return(1LL, l)
  61. #define local_dec(l) local_dec_return(l)
  62. #define local_sub_and_test(a, l) (local_sub_return((a), (l)) == 0)
  63. #define local_dec_and_test(l) (local_dec_return((l)) == 0)
  64. static __inline__ long local_cmpxchg(local_t *l, long o, long n)
  65. {
  66. long t;
  67. unsigned long flags;
  68. powerpc_local_irq_pmu_save(flags);
  69. t = l->v;
  70. if (t == o)
  71. l->v = n;
  72. powerpc_local_irq_pmu_restore(flags);
  73. return t;
  74. }
  75. static __inline__ long local_xchg(local_t *l, long n)
  76. {
  77. long t;
  78. unsigned long flags;
  79. powerpc_local_irq_pmu_save(flags);
  80. t = l->v;
  81. l->v = n;
  82. powerpc_local_irq_pmu_restore(flags);
  83. return t;
  84. }
  85. /**
  86. * local_add_unless - add unless the number is a given value
  87. * @l: pointer of type local_t
  88. * @a: the amount to add to v...
  89. * @u: ...unless v is equal to u.
  90. *
  91. * Atomically adds @a to @l, so long as it was not @u.
  92. * Returns non-zero if @l was not @u, and zero otherwise.
  93. */
  94. static __inline__ int local_add_unless(local_t *l, long a, long u)
  95. {
  96. unsigned long flags;
  97. int ret = 0;
  98. powerpc_local_irq_pmu_save(flags);
  99. if (l->v != u) {
  100. l->v += a;
  101. ret = 1;
  102. }
  103. powerpc_local_irq_pmu_restore(flags);
  104. return ret;
  105. }
  106. #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
  107. /* Use these for per-cpu local_t variables: on some archs they are
  108. * much more efficient than these naive implementations. Note they take
  109. * a variable, not an address.
  110. */
  111. #define __local_inc(l) ((l)->v++)
  112. #define __local_dec(l) ((l)->v++)
  113. #define __local_add(i,l) ((l)->v+=(i))
  114. #define __local_sub(i,l) ((l)->v-=(i))
  115. #else /* CONFIG_PPC64 */
  116. #include <asm-generic/local.h>
  117. #endif /* CONFIG_PPC64 */
  118. #endif /* _ARCH_POWERPC_LOCAL_H */