diff options
author | Waiman Long <Waiman.Long@hpe.com> | 2015-11-09 19:09:21 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-11-23 04:01:58 -0500 |
commit | 64d816cba06c67eeee455b8c78ebcda349d49c24 (patch) | |
tree | 4f84909ad1dbf50bfc038dde2e72285f8e98521e | |
parent | 978e5a3692c3b674b4c7c412e96835fd996c2ff4 (diff) |
locking/qspinlock: Use _acquire/_release() versions of cmpxchg() & xchg()
This patch replaces the cmpxchg() and xchg() calls in the native
qspinlock code with the more relaxed _acquire or _release versions of
those calls to enable other architectures to adopt queued spinlocks
with less memory barrier performance overhead.
Signed-off-by: Waiman Long <Waiman.Long@hpe.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Douglas Hatch <doug.hatch@hpe.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Scott J Norton <scott.norton@hpe.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1447114167-47185-2-git-send-email-Waiman.Long@hpe.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | include/asm-generic/qspinlock.h | 9 | ||||
-rw-r--r-- | kernel/locking/qspinlock.c | 29 |
2 files changed, 29 insertions, 9 deletions
diff --git a/include/asm-generic/qspinlock.h b/include/asm-generic/qspinlock.h index e2aadbc7151f..39e1cb201b8e 100644 --- a/include/asm-generic/qspinlock.h +++ b/include/asm-generic/qspinlock.h | |||
@@ -12,8 +12,9 @@ | |||
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P. | 14 | * (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P. |
15 | * (C) Copyright 2015 Hewlett-Packard Enterprise Development LP | ||
15 | * | 16 | * |
16 | * Authors: Waiman Long <waiman.long@hp.com> | 17 | * Authors: Waiman Long <waiman.long@hpe.com> |
17 | */ | 18 | */ |
18 | #ifndef __ASM_GENERIC_QSPINLOCK_H | 19 | #ifndef __ASM_GENERIC_QSPINLOCK_H |
19 | #define __ASM_GENERIC_QSPINLOCK_H | 20 | #define __ASM_GENERIC_QSPINLOCK_H |
@@ -62,7 +63,7 @@ static __always_inline int queued_spin_is_contended(struct qspinlock *lock) | |||
62 | static __always_inline int queued_spin_trylock(struct qspinlock *lock) | 63 | static __always_inline int queued_spin_trylock(struct qspinlock *lock) |
63 | { | 64 | { |
64 | if (!atomic_read(&lock->val) && | 65 | if (!atomic_read(&lock->val) && |
65 | (atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL) == 0)) | 66 | (atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL) == 0)) |
66 | return 1; | 67 | return 1; |
67 | return 0; | 68 | return 0; |
68 | } | 69 | } |
@@ -77,7 +78,7 @@ static __always_inline void queued_spin_lock(struct qspinlock *lock) | |||
77 | { | 78 | { |
78 | u32 val; | 79 | u32 val; |
79 | 80 | ||
80 | val = atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL); | 81 | val = atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL); |
81 | if (likely(val == 0)) | 82 | if (likely(val == 0)) |
82 | return; | 83 | return; |
83 | queued_spin_lock_slowpath(lock, val); | 84 | queued_spin_lock_slowpath(lock, val); |
@@ -93,7 +94,7 @@ static __always_inline void queued_spin_unlock(struct qspinlock *lock) | |||
93 | /* | 94 | /* |
94 | * smp_mb__before_atomic() in order to guarantee release semantics | 95 | * smp_mb__before_atomic() in order to guarantee release semantics |
95 | */ | 96 | */ |
96 | smp_mb__before_atomic_dec(); | 97 | smp_mb__before_atomic(); |
97 | atomic_sub(_Q_LOCKED_VAL, &lock->val); | 98 | atomic_sub(_Q_LOCKED_VAL, &lock->val); |
98 | } | 99 | } |
99 | #endif | 100 | #endif |
diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index 87e9ce6a63c5..7868418ea586 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c | |||
@@ -14,8 +14,9 @@ | |||
14 | * (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P. | 14 | * (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P. |
15 | * (C) Copyright 2013-2014 Red Hat, Inc. | 15 | * (C) Copyright 2013-2014 Red Hat, Inc. |
16 | * (C) Copyright 2015 Intel Corp. | 16 | * (C) Copyright 2015 Intel Corp. |
17 | * (C) Copyright 2015 Hewlett-Packard Enterprise Development LP | ||
17 | * | 18 | * |
18 | * Authors: Waiman Long <waiman.long@hp.com> | 19 | * Authors: Waiman Long <waiman.long@hpe.com> |
19 | * Peter Zijlstra <peterz@infradead.org> | 20 | * Peter Zijlstra <peterz@infradead.org> |
20 | */ | 21 | */ |
21 | 22 | ||
@@ -176,7 +177,12 @@ static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail) | |||
176 | { | 177 | { |
177 | struct __qspinlock *l = (void *)lock; | 178 | struct __qspinlock *l = (void *)lock; |
178 | 179 | ||
179 | return (u32)xchg(&l->tail, tail >> _Q_TAIL_OFFSET) << _Q_TAIL_OFFSET; | 180 | /* |
181 | * Use release semantics to make sure that the MCS node is properly | ||
182 | * initialized before changing the tail code. | ||
183 | */ | ||
184 | return (u32)xchg_release(&l->tail, | ||
185 | tail >> _Q_TAIL_OFFSET) << _Q_TAIL_OFFSET; | ||
180 | } | 186 | } |
181 | 187 | ||
182 | #else /* _Q_PENDING_BITS == 8 */ | 188 | #else /* _Q_PENDING_BITS == 8 */ |
@@ -208,7 +214,11 @@ static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail) | |||
208 | 214 | ||
209 | for (;;) { | 215 | for (;;) { |
210 | new = (val & _Q_LOCKED_PENDING_MASK) | tail; | 216 | new = (val & _Q_LOCKED_PENDING_MASK) | tail; |
211 | old = atomic_cmpxchg(&lock->val, val, new); | 217 | /* |
218 | * Use release semantics to make sure that the MCS node is | ||
219 | * properly initialized before changing the tail code. | ||
220 | */ | ||
221 | old = atomic_cmpxchg_release(&lock->val, val, new); | ||
212 | if (old == val) | 222 | if (old == val) |
213 | break; | 223 | break; |
214 | 224 | ||
@@ -319,7 +329,11 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) | |||
319 | if (val == new) | 329 | if (val == new) |
320 | new |= _Q_PENDING_VAL; | 330 | new |= _Q_PENDING_VAL; |
321 | 331 | ||
322 | old = atomic_cmpxchg(&lock->val, val, new); | 332 | /* |
333 | * Acquire semantic is required here as the function may | ||
334 | * return immediately if the lock was free. | ||
335 | */ | ||
336 | old = atomic_cmpxchg_acquire(&lock->val, val, new); | ||
323 | if (old == val) | 337 | if (old == val) |
324 | break; | 338 | break; |
325 | 339 | ||
@@ -426,7 +440,12 @@ queue: | |||
426 | set_locked(lock); | 440 | set_locked(lock); |
427 | break; | 441 | break; |
428 | } | 442 | } |
429 | old = atomic_cmpxchg(&lock->val, val, _Q_LOCKED_VAL); | 443 | /* |
444 | * The smp_load_acquire() call above has provided the necessary | ||
445 | * acquire semantics required for locking. At most two | ||
446 | * iterations of this loop may be ran. | ||
447 | */ | ||
448 | old = atomic_cmpxchg_relaxed(&lock->val, val, _Q_LOCKED_VAL); | ||
430 | if (old == val) | 449 | if (old == val) |
431 | goto release; /* No contention */ | 450 | goto release; /* No contention */ |
432 | 451 | ||