summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2018-04-26 06:34:15 -0400
committerIngo Molnar <mingo@kernel.org>2018-04-27 03:48:44 -0400
commitfcfdfe30e324725007e9dc5814b62a4c430ea909 (patch)
tree21ef852058607e75e1130f198abf7f958fb26d8f
parent0644f186fc9d77bb5bd198369e59fb28927a3692 (diff)
locking/barriers: Introduce smp_cond_load_relaxed() and atomic_cond_read_relaxed()
Whilst we currently provide smp_cond_load_acquire() and atomic_cond_read_acquire(), there are cases where the ACQUIRE semantics are not required because of a subsequent fence or release operation once the conditional loop has exited. This patch adds relaxed versions of the conditional spinning primitives to avoid unnecessary barrier overhead on architectures such as arm64. Signed-off-by: Will Deacon <will.deacon@arm.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Waiman Long <longman@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: boqun.feng@gmail.com Cc: linux-arm-kernel@lists.infradead.org Cc: paulmck@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/1524738868-31318-2-git-send-email-will.deacon@arm.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/asm-generic/atomic-long.h2
-rw-r--r--include/asm-generic/barrier.h27
-rw-r--r--include/linux/atomic.h2
3 files changed, 25 insertions, 6 deletions
diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h
index 34a028a7bcc5..5b2b0b5ea06d 100644
--- a/include/asm-generic/atomic-long.h
+++ b/include/asm-generic/atomic-long.h
@@ -244,6 +244,8 @@ static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
244#define atomic_long_inc_not_zero(l) \ 244#define atomic_long_inc_not_zero(l) \
245 ATOMIC_LONG_PFX(_inc_not_zero)((ATOMIC_LONG_PFX(_t) *)(l)) 245 ATOMIC_LONG_PFX(_inc_not_zero)((ATOMIC_LONG_PFX(_t) *)(l))
246 246
247#define atomic_long_cond_read_relaxed(v, c) \
248 ATOMIC_LONG_PFX(_cond_read_relaxed)((ATOMIC_LONG_PFX(_t) *)(v), (c))
247#define atomic_long_cond_read_acquire(v, c) \ 249#define atomic_long_cond_read_acquire(v, c) \
248 ATOMIC_LONG_PFX(_cond_read_acquire)((ATOMIC_LONG_PFX(_t) *)(v), (c)) 250 ATOMIC_LONG_PFX(_cond_read_acquire)((ATOMIC_LONG_PFX(_t) *)(v), (c))
249 251
diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
index 29458bbb2fa0..2cafdbb9ae4c 100644
--- a/include/asm-generic/barrier.h
+++ b/include/asm-generic/barrier.h
@@ -221,18 +221,17 @@ do { \
221#endif 221#endif
222 222
223/** 223/**
224 * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering 224 * smp_cond_load_relaxed() - (Spin) wait for cond with no ordering guarantees
225 * @ptr: pointer to the variable to wait on 225 * @ptr: pointer to the variable to wait on
226 * @cond: boolean expression to wait for 226 * @cond: boolean expression to wait for
227 * 227 *
228 * Equivalent to using smp_load_acquire() on the condition variable but employs 228 * Equivalent to using READ_ONCE() on the condition variable.
229 * the control dependency of the wait to reduce the barrier on many platforms.
230 * 229 *
231 * Due to C lacking lambda expressions we load the value of *ptr into a 230 * Due to C lacking lambda expressions we load the value of *ptr into a
232 * pre-named variable @VAL to be used in @cond. 231 * pre-named variable @VAL to be used in @cond.
233 */ 232 */
234#ifndef smp_cond_load_acquire 233#ifndef smp_cond_load_relaxed
235#define smp_cond_load_acquire(ptr, cond_expr) ({ \ 234#define smp_cond_load_relaxed(ptr, cond_expr) ({ \
236 typeof(ptr) __PTR = (ptr); \ 235 typeof(ptr) __PTR = (ptr); \
237 typeof(*ptr) VAL; \ 236 typeof(*ptr) VAL; \
238 for (;;) { \ 237 for (;;) { \
@@ -241,10 +240,26 @@ do { \
241 break; \ 240 break; \
242 cpu_relax(); \ 241 cpu_relax(); \
243 } \ 242 } \
244 smp_acquire__after_ctrl_dep(); \
245 VAL; \ 243 VAL; \
246}) 244})
247#endif 245#endif
248 246
247/**
248 * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering
249 * @ptr: pointer to the variable to wait on
250 * @cond: boolean expression to wait for
251 *
252 * Equivalent to using smp_load_acquire() on the condition variable but employs
253 * the control dependency of the wait to reduce the barrier on many platforms.
254 */
255#ifndef smp_cond_load_acquire
256#define smp_cond_load_acquire(ptr, cond_expr) ({ \
257 typeof(*ptr) _val; \
258 _val = smp_cond_load_relaxed(ptr, cond_expr); \
259 smp_acquire__after_ctrl_dep(); \
260 _val; \
261})
262#endif
263
249#endif /* !__ASSEMBLY__ */ 264#endif /* !__ASSEMBLY__ */
250#endif /* __ASM_GENERIC_BARRIER_H */ 265#endif /* __ASM_GENERIC_BARRIER_H */
diff --git a/include/linux/atomic.h b/include/linux/atomic.h
index 8b276fd9a127..01ce3997cb42 100644
--- a/include/linux/atomic.h
+++ b/include/linux/atomic.h
@@ -654,6 +654,7 @@ static inline int atomic_dec_if_positive(atomic_t *v)
654} 654}
655#endif 655#endif
656 656
657#define atomic_cond_read_relaxed(v, c) smp_cond_load_relaxed(&(v)->counter, (c))
657#define atomic_cond_read_acquire(v, c) smp_cond_load_acquire(&(v)->counter, (c)) 658#define atomic_cond_read_acquire(v, c) smp_cond_load_acquire(&(v)->counter, (c))
658 659
659#ifdef CONFIG_GENERIC_ATOMIC64 660#ifdef CONFIG_GENERIC_ATOMIC64
@@ -1075,6 +1076,7 @@ static inline long long atomic64_fetch_andnot_release(long long i, atomic64_t *v
1075} 1076}
1076#endif 1077#endif
1077 1078
1079#define atomic64_cond_read_relaxed(v, c) smp_cond_load_relaxed(&(v)->counter, (c))
1078#define atomic64_cond_read_acquire(v, c) smp_cond_load_acquire(&(v)->counter, (c)) 1080#define atomic64_cond_read_acquire(v, c) smp_cond_load_acquire(&(v)->counter, (c))
1079 1081
1080#include <asm-generic/atomic-long.h> 1082#include <asm-generic/atomic-long.h>