mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
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:
commit
c86ad14d30
108 changed files with 3268 additions and 958 deletions
|
|
@ -112,6 +112,62 @@ static __always_inline void atomic_long_dec(atomic_long_t *l)
|
|||
ATOMIC_LONG_PFX(_dec)(v);
|
||||
}
|
||||
|
||||
#define ATOMIC_LONG_FETCH_OP(op, mo) \
|
||||
static inline long \
|
||||
atomic_long_fetch_##op##mo(long i, atomic_long_t *l) \
|
||||
{ \
|
||||
ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \
|
||||
\
|
||||
return (long)ATOMIC_LONG_PFX(_fetch_##op##mo)(i, v); \
|
||||
}
|
||||
|
||||
ATOMIC_LONG_FETCH_OP(add, )
|
||||
ATOMIC_LONG_FETCH_OP(add, _relaxed)
|
||||
ATOMIC_LONG_FETCH_OP(add, _acquire)
|
||||
ATOMIC_LONG_FETCH_OP(add, _release)
|
||||
ATOMIC_LONG_FETCH_OP(sub, )
|
||||
ATOMIC_LONG_FETCH_OP(sub, _relaxed)
|
||||
ATOMIC_LONG_FETCH_OP(sub, _acquire)
|
||||
ATOMIC_LONG_FETCH_OP(sub, _release)
|
||||
ATOMIC_LONG_FETCH_OP(and, )
|
||||
ATOMIC_LONG_FETCH_OP(and, _relaxed)
|
||||
ATOMIC_LONG_FETCH_OP(and, _acquire)
|
||||
ATOMIC_LONG_FETCH_OP(and, _release)
|
||||
ATOMIC_LONG_FETCH_OP(andnot, )
|
||||
ATOMIC_LONG_FETCH_OP(andnot, _relaxed)
|
||||
ATOMIC_LONG_FETCH_OP(andnot, _acquire)
|
||||
ATOMIC_LONG_FETCH_OP(andnot, _release)
|
||||
ATOMIC_LONG_FETCH_OP(or, )
|
||||
ATOMIC_LONG_FETCH_OP(or, _relaxed)
|
||||
ATOMIC_LONG_FETCH_OP(or, _acquire)
|
||||
ATOMIC_LONG_FETCH_OP(or, _release)
|
||||
ATOMIC_LONG_FETCH_OP(xor, )
|
||||
ATOMIC_LONG_FETCH_OP(xor, _relaxed)
|
||||
ATOMIC_LONG_FETCH_OP(xor, _acquire)
|
||||
ATOMIC_LONG_FETCH_OP(xor, _release)
|
||||
|
||||
#undef ATOMIC_LONG_FETCH_OP
|
||||
|
||||
#define ATOMIC_LONG_FETCH_INC_DEC_OP(op, mo) \
|
||||
static inline long \
|
||||
atomic_long_fetch_##op##mo(atomic_long_t *l) \
|
||||
{ \
|
||||
ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \
|
||||
\
|
||||
return (long)ATOMIC_LONG_PFX(_fetch_##op##mo)(v); \
|
||||
}
|
||||
|
||||
ATOMIC_LONG_FETCH_INC_DEC_OP(inc,)
|
||||
ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _relaxed)
|
||||
ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _acquire)
|
||||
ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _release)
|
||||
ATOMIC_LONG_FETCH_INC_DEC_OP(dec,)
|
||||
ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _relaxed)
|
||||
ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _acquire)
|
||||
ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _release)
|
||||
|
||||
#undef ATOMIC_LONG_FETCH_INC_DEC_OP
|
||||
|
||||
#define ATOMIC_LONG_OP(op) \
|
||||
static __always_inline void \
|
||||
atomic_long_##op(long i, atomic_long_t *l) \
|
||||
|
|
@ -124,9 +180,9 @@ atomic_long_##op(long i, atomic_long_t *l) \
|
|||
ATOMIC_LONG_OP(add)
|
||||
ATOMIC_LONG_OP(sub)
|
||||
ATOMIC_LONG_OP(and)
|
||||
ATOMIC_LONG_OP(andnot)
|
||||
ATOMIC_LONG_OP(or)
|
||||
ATOMIC_LONG_OP(xor)
|
||||
ATOMIC_LONG_OP(andnot)
|
||||
|
||||
#undef ATOMIC_LONG_OP
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,18 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \
|
|||
return c c_op i; \
|
||||
}
|
||||
|
||||
#define ATOMIC_FETCH_OP(op, c_op) \
|
||||
static inline int atomic_fetch_##op(int i, atomic_t *v) \
|
||||
{ \
|
||||
int c, old; \
|
||||
\
|
||||
c = v->counter; \
|
||||
while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \
|
||||
c = old; \
|
||||
\
|
||||
return c; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <linux/irqflags.h>
|
||||
|
|
@ -88,6 +100,20 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \
|
|||
return ret; \
|
||||
}
|
||||
|
||||
#define ATOMIC_FETCH_OP(op, c_op) \
|
||||
static inline int atomic_fetch_##op(int i, atomic_t *v) \
|
||||
{ \
|
||||
unsigned long flags; \
|
||||
int ret; \
|
||||
\
|
||||
raw_local_irq_save(flags); \
|
||||
ret = v->counter; \
|
||||
v->counter = v->counter c_op i; \
|
||||
raw_local_irq_restore(flags); \
|
||||
\
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
#ifndef atomic_add_return
|
||||
|
|
@ -98,6 +124,26 @@ ATOMIC_OP_RETURN(add, +)
|
|||
ATOMIC_OP_RETURN(sub, -)
|
||||
#endif
|
||||
|
||||
#ifndef atomic_fetch_add
|
||||
ATOMIC_FETCH_OP(add, +)
|
||||
#endif
|
||||
|
||||
#ifndef atomic_fetch_sub
|
||||
ATOMIC_FETCH_OP(sub, -)
|
||||
#endif
|
||||
|
||||
#ifndef atomic_fetch_and
|
||||
ATOMIC_FETCH_OP(and, &)
|
||||
#endif
|
||||
|
||||
#ifndef atomic_fetch_or
|
||||
ATOMIC_FETCH_OP(or, |)
|
||||
#endif
|
||||
|
||||
#ifndef atomic_fetch_xor
|
||||
ATOMIC_FETCH_OP(xor, ^)
|
||||
#endif
|
||||
|
||||
#ifndef atomic_and
|
||||
ATOMIC_OP(and, &)
|
||||
#endif
|
||||
|
|
@ -110,6 +156,7 @@ ATOMIC_OP(or, |)
|
|||
ATOMIC_OP(xor, ^)
|
||||
#endif
|
||||
|
||||
#undef ATOMIC_FETCH_OP
|
||||
#undef ATOMIC_OP_RETURN
|
||||
#undef ATOMIC_OP
|
||||
|
||||
|
|
|
|||
|
|
@ -27,16 +27,23 @@ extern void atomic64_##op(long long a, atomic64_t *v);
|
|||
#define ATOMIC64_OP_RETURN(op) \
|
||||
extern long long atomic64_##op##_return(long long a, atomic64_t *v);
|
||||
|
||||
#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op)
|
||||
#define ATOMIC64_FETCH_OP(op) \
|
||||
extern long long atomic64_fetch_##op(long long a, atomic64_t *v);
|
||||
|
||||
#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_FETCH_OP(op)
|
||||
|
||||
ATOMIC64_OPS(add)
|
||||
ATOMIC64_OPS(sub)
|
||||
|
||||
ATOMIC64_OP(and)
|
||||
ATOMIC64_OP(or)
|
||||
ATOMIC64_OP(xor)
|
||||
#undef ATOMIC64_OPS
|
||||
#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_FETCH_OP(op)
|
||||
|
||||
ATOMIC64_OPS(and)
|
||||
ATOMIC64_OPS(or)
|
||||
ATOMIC64_OPS(xor)
|
||||
|
||||
#undef ATOMIC64_OPS
|
||||
#undef ATOMIC64_FETCH_OP
|
||||
#undef ATOMIC64_OP_RETURN
|
||||
#undef ATOMIC64_OP
|
||||
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ do { \
|
|||
})
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
/* Barriers for virtual machine guests when talking to an SMP host */
|
||||
#define virt_mb() __smp_mb()
|
||||
|
|
@ -207,5 +207,44 @@ do { \
|
|||
#define virt_store_release(p, v) __smp_store_release(p, v)
|
||||
#define virt_load_acquire(p) __smp_load_acquire(p)
|
||||
|
||||
/**
|
||||
* smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency
|
||||
*
|
||||
* A control dependency provides a LOAD->STORE order, the additional RMB
|
||||
* provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order,
|
||||
* aka. (load)-ACQUIRE.
|
||||
*
|
||||
* Architectures that do not do load speculation can have this be barrier().
|
||||
*/
|
||||
#ifndef smp_acquire__after_ctrl_dep
|
||||
#define smp_acquire__after_ctrl_dep() smp_rmb()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering
|
||||
* @ptr: pointer to the variable to wait on
|
||||
* @cond: boolean expression to wait for
|
||||
*
|
||||
* Equivalent to using smp_load_acquire() on the condition variable but employs
|
||||
* the control dependency of the wait to reduce the barrier on many platforms.
|
||||
*
|
||||
* Due to C lacking lambda expressions we load the value of *ptr into a
|
||||
* pre-named variable @VAL to be used in @cond.
|
||||
*/
|
||||
#ifndef smp_cond_load_acquire
|
||||
#define smp_cond_load_acquire(ptr, cond_expr) ({ \
|
||||
typeof(ptr) __PTR = (ptr); \
|
||||
typeof(*ptr) VAL; \
|
||||
for (;;) { \
|
||||
VAL = READ_ONCE(*__PTR); \
|
||||
if (cond_expr) \
|
||||
break; \
|
||||
cpu_relax(); \
|
||||
} \
|
||||
smp_acquire__after_ctrl_dep(); \
|
||||
VAL; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
#endif /* __ASM_GENERIC_BARRIER_H */
|
||||
|
|
|
|||
|
|
@ -80,7 +80,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 (likely(atomic_cmpxchg_acquire(count, 1, 0) == 1))
|
||||
if (likely(atomic_read(count) == 1 && atomic_cmpxchg_acquire(count, 1, 0) == 1))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,8 +91,12 @@ __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 *))
|
||||
{
|
||||
int prev = atomic_xchg_acquire(count, 0);
|
||||
int prev;
|
||||
|
||||
if (atomic_read(count) != 1)
|
||||
return 0;
|
||||
|
||||
prev = atomic_xchg_acquire(count, 0);
|
||||
if (unlikely(prev < 0)) {
|
||||
/*
|
||||
* The lock was marked contended so we must restore that
|
||||
|
|
|
|||
|
|
@ -111,10 +111,9 @@ static __always_inline void queued_spin_lock(struct qspinlock *lock)
|
|||
static __always_inline void queued_spin_unlock(struct qspinlock *lock)
|
||||
{
|
||||
/*
|
||||
* smp_mb__before_atomic() in order to guarantee release semantics
|
||||
* unlock() needs release semantics:
|
||||
*/
|
||||
smp_mb__before_atomic();
|
||||
atomic_sub(_Q_LOCKED_VAL, &lock->val);
|
||||
(void)atomic_sub_return_release(_Q_LOCKED_VAL, &lock->val);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
|
|||
{
|
||||
long tmp;
|
||||
|
||||
while ((tmp = sem->count) >= 0) {
|
||||
if (tmp == cmpxchg_acquire(&sem->count, tmp,
|
||||
while ((tmp = atomic_long_read(&sem->count)) >= 0) {
|
||||
if (tmp == atomic_long_cmpxchg_acquire(&sem->count, tmp,
|
||||
tmp + RWSEM_ACTIVE_READ_BIAS)) {
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
|
|||
{
|
||||
long tmp;
|
||||
|
||||
tmp = cmpxchg_acquire(&sem->count, RWSEM_UNLOCKED_VALUE,
|
||||
tmp = atomic_long_cmpxchg_acquire(&sem->count, RWSEM_UNLOCKED_VALUE,
|
||||
RWSEM_ACTIVE_WRITE_BIAS);
|
||||
return tmp == RWSEM_UNLOCKED_VALUE;
|
||||
}
|
||||
|
|
@ -106,14 +106,6 @@ static inline void __up_write(struct rw_semaphore *sem)
|
|||
rwsem_wake(sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* implement atomic add functionality
|
||||
*/
|
||||
static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
|
||||
{
|
||||
atomic_long_add(delta, (atomic_long_t *)&sem->count);
|
||||
}
|
||||
|
||||
/*
|
||||
* downgrade write lock to read lock
|
||||
*/
|
||||
|
|
@ -134,13 +126,5 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
|
|||
rwsem_downgrade_wake(sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* implement exchange and add functionality
|
||||
*/
|
||||
static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
|
||||
{
|
||||
return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _ASM_GENERIC_RWSEM_H */
|
||||
|
|
|
|||
Loading…
Reference in a new issue