Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull locking updates from Ingo Molnar: "The locking tree was busier in this cycle than the usual pattern - a couple of major projects happened to coincide. The main changes are: - implement the atomic_fetch_{add,sub,and,or,xor}() API natively across all SMP architectures (Peter Zijlstra) - add atomic_fetch_{inc/dec}() as well, using the generic primitives (Davidlohr Bueso) - optimize various aspects of rwsems (Jason Low, Davidlohr Bueso, Waiman Long) - optimize smp_cond_load_acquire() on arm64 and implement LSE based atomic{,64}_fetch_{add,sub,and,andnot,or,xor}{,_relaxed,_acquire,_release}() on arm64 (Will Deacon) - introduce smp_acquire__after_ctrl_dep() and fix various barrier mis-uses and bugs (Peter Zijlstra) - after discovering ancient spin_unlock_wait() barrier bugs in its implementation and usage, strengthen its semantics and update/fix usage sites (Peter Zijlstra) - optimize mutex_trylock() fastpath (Peter Zijlstra) - ... misc fixes and cleanups" * 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (67 commits) locking/atomic: Introduce inc/dec variants for the atomic_fetch_$op() API locking/barriers, arch/arm64: Implement LDXR+WFE based smp_cond_load_acquire() locking/static_keys: Fix non static symbol Sparse warning locking/qspinlock: Use __this_cpu_dec() instead of full-blown this_cpu_dec() locking/atomic, arch/tile: Fix tilepro build locking/atomic, arch/m68k: Remove comment locking/atomic, arch/arc: Fix build locking/Documentation: Clarify limited control-dependency scope locking/atomic, arch/rwsem: Employ atomic_long_fetch_add() locking/atomic, arch/qrwlock: Employ atomic_fetch_add_acquire() locking/atomic, arch/mips: Convert to _relaxed atomics locking/atomic, arch/alpha: Convert to _relaxed atomics locking/atomic: Remove the deprecated atomic_{set,clear}_mask() functions locking/atomic: Remove linux/atomic.h:atomic_fetch_or() locking/atomic: Implement atomic{,64,_long}_fetch_{add,sub,and,andnot,or,xor}{,_relaxed,_acquire,_release}() locking/atomic: Fix atomic64_relaxed() bits locking/atomic, arch/xtensa: Implement atomic_fetch_{add,sub,and,or,xor}() locking/atomic, arch/x86: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() locking/atomic, arch/tile: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() locking/atomic, arch/sparc: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() ...
This commit is contained in:
@@ -42,8 +42,27 @@ ia64_atomic_##op (int i, atomic_t *v) \
|
||||
return new; \
|
||||
}
|
||||
|
||||
ATOMIC_OP(add, +)
|
||||
ATOMIC_OP(sub, -)
|
||||
#define ATOMIC_FETCH_OP(op, c_op) \
|
||||
static __inline__ int \
|
||||
ia64_atomic_fetch_##op (int i, atomic_t *v) \
|
||||
{ \
|
||||
__s32 old, new; \
|
||||
CMPXCHG_BUGCHECK_DECL \
|
||||
\
|
||||
do { \
|
||||
CMPXCHG_BUGCHECK(v); \
|
||||
old = atomic_read(v); \
|
||||
new = old c_op i; \
|
||||
} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \
|
||||
return old; \
|
||||
}
|
||||
|
||||
#define ATOMIC_OPS(op, c_op) \
|
||||
ATOMIC_OP(op, c_op) \
|
||||
ATOMIC_FETCH_OP(op, c_op)
|
||||
|
||||
ATOMIC_OPS(add, +)
|
||||
ATOMIC_OPS(sub, -)
|
||||
|
||||
#define atomic_add_return(i,v) \
|
||||
({ \
|
||||
@@ -69,14 +88,44 @@ ATOMIC_OP(sub, -)
|
||||
: ia64_atomic_sub(__ia64_asr_i, v); \
|
||||
})
|
||||
|
||||
ATOMIC_OP(and, &)
|
||||
ATOMIC_OP(or, |)
|
||||
ATOMIC_OP(xor, ^)
|
||||
#define atomic_fetch_add(i,v) \
|
||||
({ \
|
||||
int __ia64_aar_i = (i); \
|
||||
(__builtin_constant_p(i) \
|
||||
&& ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \
|
||||
|| (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \
|
||||
|| (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \
|
||||
|| (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \
|
||||
? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \
|
||||
: ia64_atomic_fetch_add(__ia64_aar_i, v); \
|
||||
})
|
||||
|
||||
#define atomic_and(i,v) (void)ia64_atomic_and(i,v)
|
||||
#define atomic_or(i,v) (void)ia64_atomic_or(i,v)
|
||||
#define atomic_xor(i,v) (void)ia64_atomic_xor(i,v)
|
||||
#define atomic_fetch_sub(i,v) \
|
||||
({ \
|
||||
int __ia64_asr_i = (i); \
|
||||
(__builtin_constant_p(i) \
|
||||
&& ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \
|
||||
|| (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \
|
||||
|| (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \
|
||||
|| (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \
|
||||
? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \
|
||||
: ia64_atomic_fetch_sub(__ia64_asr_i, v); \
|
||||
})
|
||||
|
||||
ATOMIC_FETCH_OP(and, &)
|
||||
ATOMIC_FETCH_OP(or, |)
|
||||
ATOMIC_FETCH_OP(xor, ^)
|
||||
|
||||
#define atomic_and(i,v) (void)ia64_atomic_fetch_and(i,v)
|
||||
#define atomic_or(i,v) (void)ia64_atomic_fetch_or(i,v)
|
||||
#define atomic_xor(i,v) (void)ia64_atomic_fetch_xor(i,v)
|
||||
|
||||
#define atomic_fetch_and(i,v) ia64_atomic_fetch_and(i,v)
|
||||
#define atomic_fetch_or(i,v) ia64_atomic_fetch_or(i,v)
|
||||
#define atomic_fetch_xor(i,v) ia64_atomic_fetch_xor(i,v)
|
||||
|
||||
#undef ATOMIC_OPS
|
||||
#undef ATOMIC_FETCH_OP
|
||||
#undef ATOMIC_OP
|
||||
|
||||
#define ATOMIC64_OP(op, c_op) \
|
||||
@@ -94,8 +143,27 @@ ia64_atomic64_##op (__s64 i, atomic64_t *v) \
|
||||
return new; \
|
||||
}
|
||||
|
||||
ATOMIC64_OP(add, +)
|
||||
ATOMIC64_OP(sub, -)
|
||||
#define ATOMIC64_FETCH_OP(op, c_op) \
|
||||
static __inline__ long \
|
||||
ia64_atomic64_fetch_##op (__s64 i, atomic64_t *v) \
|
||||
{ \
|
||||
__s64 old, new; \
|
||||
CMPXCHG_BUGCHECK_DECL \
|
||||
\
|
||||
do { \
|
||||
CMPXCHG_BUGCHECK(v); \
|
||||
old = atomic64_read(v); \
|
||||
new = old c_op i; \
|
||||
} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \
|
||||
return old; \
|
||||
}
|
||||
|
||||
#define ATOMIC64_OPS(op, c_op) \
|
||||
ATOMIC64_OP(op, c_op) \
|
||||
ATOMIC64_FETCH_OP(op, c_op)
|
||||
|
||||
ATOMIC64_OPS(add, +)
|
||||
ATOMIC64_OPS(sub, -)
|
||||
|
||||
#define atomic64_add_return(i,v) \
|
||||
({ \
|
||||
@@ -121,14 +189,44 @@ ATOMIC64_OP(sub, -)
|
||||
: ia64_atomic64_sub(__ia64_asr_i, v); \
|
||||
})
|
||||
|
||||
ATOMIC64_OP(and, &)
|
||||
ATOMIC64_OP(or, |)
|
||||
ATOMIC64_OP(xor, ^)
|
||||
#define atomic64_fetch_add(i,v) \
|
||||
({ \
|
||||
long __ia64_aar_i = (i); \
|
||||
(__builtin_constant_p(i) \
|
||||
&& ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \
|
||||
|| (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \
|
||||
|| (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \
|
||||
|| (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \
|
||||
? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \
|
||||
: ia64_atomic64_fetch_add(__ia64_aar_i, v); \
|
||||
})
|
||||
|
||||
#define atomic64_and(i,v) (void)ia64_atomic64_and(i,v)
|
||||
#define atomic64_or(i,v) (void)ia64_atomic64_or(i,v)
|
||||
#define atomic64_xor(i,v) (void)ia64_atomic64_xor(i,v)
|
||||
#define atomic64_fetch_sub(i,v) \
|
||||
({ \
|
||||
long __ia64_asr_i = (i); \
|
||||
(__builtin_constant_p(i) \
|
||||
&& ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \
|
||||
|| (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \
|
||||
|| (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \
|
||||
|| (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \
|
||||
? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \
|
||||
: ia64_atomic64_fetch_sub(__ia64_asr_i, v); \
|
||||
})
|
||||
|
||||
ATOMIC64_FETCH_OP(and, &)
|
||||
ATOMIC64_FETCH_OP(or, |)
|
||||
ATOMIC64_FETCH_OP(xor, ^)
|
||||
|
||||
#define atomic64_and(i,v) (void)ia64_atomic64_fetch_and(i,v)
|
||||
#define atomic64_or(i,v) (void)ia64_atomic64_fetch_or(i,v)
|
||||
#define atomic64_xor(i,v) (void)ia64_atomic64_fetch_xor(i,v)
|
||||
|
||||
#define atomic64_fetch_and(i,v) ia64_atomic64_fetch_and(i,v)
|
||||
#define atomic64_fetch_or(i,v) ia64_atomic64_fetch_or(i,v)
|
||||
#define atomic64_fetch_xor(i,v) ia64_atomic64_fetch_xor(i,v)
|
||||
|
||||
#undef ATOMIC64_OPS
|
||||
#undef ATOMIC64_FETCH_OP
|
||||
#undef ATOMIC64_OP
|
||||
|
||||
#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
|
||||
|
@@ -82,7 +82,7 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
static inline int
|
||||
__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
|
||||
{
|
||||
if (cmpxchg_acq(count, 1, 0) == 1)
|
||||
if (atomic_read(count) == 1 && cmpxchg_acq(count, 1, 0) == 1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@
|
||||
static inline void
|
||||
__down_read (struct rw_semaphore *sem)
|
||||
{
|
||||
long result = ia64_fetchadd8_acq((unsigned long *)&sem->count, 1);
|
||||
long result = ia64_fetchadd8_acq((unsigned long *)&sem->count.counter, 1);
|
||||
|
||||
if (result < 0)
|
||||
rwsem_down_read_failed(sem);
|
||||
@@ -55,9 +55,9 @@ ___down_write (struct rw_semaphore *sem)
|
||||
long old, new;
|
||||
|
||||
do {
|
||||
old = sem->count;
|
||||
old = atomic_long_read(&sem->count);
|
||||
new = old + RWSEM_ACTIVE_WRITE_BIAS;
|
||||
} while (cmpxchg_acq(&sem->count, old, new) != old);
|
||||
} while (atomic_long_cmpxchg_acquire(&sem->count, old, new) != old);
|
||||
|
||||
return old;
|
||||
}
|
||||
@@ -85,7 +85,7 @@ __down_write_killable (struct rw_semaphore *sem)
|
||||
static inline void
|
||||
__up_read (struct rw_semaphore *sem)
|
||||
{
|
||||
long result = ia64_fetchadd8_rel((unsigned long *)&sem->count, -1);
|
||||
long result = ia64_fetchadd8_rel((unsigned long *)&sem->count.counter, -1);
|
||||
|
||||
if (result < 0 && (--result & RWSEM_ACTIVE_MASK) == 0)
|
||||
rwsem_wake(sem);
|
||||
@@ -100,9 +100,9 @@ __up_write (struct rw_semaphore *sem)
|
||||
long old, new;
|
||||
|
||||
do {
|
||||
old = sem->count;
|
||||
old = atomic_long_read(&sem->count);
|
||||
new = old - RWSEM_ACTIVE_WRITE_BIAS;
|
||||
} while (cmpxchg_rel(&sem->count, old, new) != old);
|
||||
} while (atomic_long_cmpxchg_release(&sem->count, old, new) != old);
|
||||
|
||||
if (new < 0 && (new & RWSEM_ACTIVE_MASK) == 0)
|
||||
rwsem_wake(sem);
|
||||
@@ -115,8 +115,8 @@ static inline int
|
||||
__down_read_trylock (struct rw_semaphore *sem)
|
||||
{
|
||||
long tmp;
|
||||
while ((tmp = sem->count) >= 0) {
|
||||
if (tmp == cmpxchg_acq(&sem->count, tmp, tmp+1)) {
|
||||
while ((tmp = atomic_long_read(&sem->count)) >= 0) {
|
||||
if (tmp == atomic_long_cmpxchg_acquire(&sem->count, tmp, tmp+1)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -129,8 +129,8 @@ __down_read_trylock (struct rw_semaphore *sem)
|
||||
static inline int
|
||||
__down_write_trylock (struct rw_semaphore *sem)
|
||||
{
|
||||
long tmp = cmpxchg_acq(&sem->count, RWSEM_UNLOCKED_VALUE,
|
||||
RWSEM_ACTIVE_WRITE_BIAS);
|
||||
long tmp = atomic_long_cmpxchg_acquire(&sem->count,
|
||||
RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS);
|
||||
return tmp == RWSEM_UNLOCKED_VALUE;
|
||||
}
|
||||
|
||||
@@ -143,19 +143,12 @@ __downgrade_write (struct rw_semaphore *sem)
|
||||
long old, new;
|
||||
|
||||
do {
|
||||
old = sem->count;
|
||||
old = atomic_long_read(&sem->count);
|
||||
new = old - RWSEM_WAITING_BIAS;
|
||||
} while (cmpxchg_rel(&sem->count, old, new) != old);
|
||||
} while (atomic_long_cmpxchg_release(&sem->count, old, new) != old);
|
||||
|
||||
if (old < 0)
|
||||
rwsem_downgrade_wake(sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement atomic add functionality. These used to be "inline" functions, but GCC v3.1
|
||||
* doesn't quite optimize this stuff right and ends up with bad calls to fetchandadd.
|
||||
*/
|
||||
#define rwsem_atomic_add(delta, sem) atomic64_add(delta, (atomic64_t *)(&(sem)->count))
|
||||
#define rwsem_atomic_update(delta, sem) atomic64_add_return(delta, (atomic64_t *)(&(sem)->count))
|
||||
|
||||
#endif /* _ASM_IA64_RWSEM_H */
|
||||
|
@@ -15,6 +15,8 @@
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/intrinsics.h>
|
||||
#include <asm/barrier.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#define arch_spin_lock_init(x) ((x)->lock = 0)
|
||||
|
||||
@@ -86,6 +88,8 @@ static __always_inline void __ticket_spin_unlock_wait(arch_spinlock_t *lock)
|
||||
return;
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
smp_acquire__after_ctrl_dep();
|
||||
}
|
||||
|
||||
static inline int __ticket_spin_is_locked(arch_spinlock_t *lock)
|
||||
|
Reference in New Issue
Block a user