aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWaiman Long <Waiman.Long@hpe.com>2015-11-09 19:09:21 -0500
committerIngo Molnar <mingo@kernel.org>2015-11-23 04:01:58 -0500
commit64d816cba06c67eeee455b8c78ebcda349d49c24 (patch)
tree4f84909ad1dbf50bfc038dde2e72285f8e98521e
parent978e5a3692c3b674b4c7c412e96835fd996c2ff4 (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.h9
-rw-r--r--kernel/locking/qspinlock.c29
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)
62static __always_inline int queued_spin_trylock(struct qspinlock *lock) 63static __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