mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull core locking updates from Ingo Molnar:
"The main changes in this cycle are:
- Another attempt at enabling cross-release lockdep dependency
tracking (automatically part of CONFIG_PROVE_LOCKING=y), this time
with better performance and fewer false positives. (Byungchul Park)
- Introduce lockdep_assert_irqs_enabled()/disabled() and convert
open-coded equivalents to lockdep variants. (Frederic Weisbecker)
- Add down_read_killable() and use it in the VFS's iterate_dir()
method. (Kirill Tkhai)
- Convert remaining uses of ACCESS_ONCE() to
READ_ONCE()/WRITE_ONCE(). Most of the conversion was Coccinelle
driven. (Mark Rutland, Paul E. McKenney)
- Get rid of lockless_dereference(), by strengthening Alpha atomics,
strengthening READ_ONCE() with smp_read_barrier_depends() and thus
being able to convert users of lockless_dereference() to
READ_ONCE(). (Will Deacon)
- Various micro-optimizations:
- better PV qspinlocks (Waiman Long),
- better x86 barriers (Michael S. Tsirkin)
- better x86 refcounts (Kees Cook)
- ... plus other fixes and enhancements. (Borislav Petkov, Juergen
Gross, Miguel Bernal Marin)"
* 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (70 commits)
locking/x86: Use LOCK ADD for smp_mb() instead of MFENCE
rcu: Use lockdep to assert IRQs are disabled/enabled
netpoll: Use lockdep to assert IRQs are disabled/enabled
timers/posix-cpu-timers: Use lockdep to assert IRQs are disabled/enabled
sched/clock, sched/cputime: Use lockdep to assert IRQs are disabled/enabled
irq_work: Use lockdep to assert IRQs are disabled/enabled
irq/timings: Use lockdep to assert IRQs are disabled/enabled
perf/core: Use lockdep to assert IRQs are disabled/enabled
x86: Use lockdep to assert IRQs are disabled/enabled
smp/core: Use lockdep to assert IRQs are disabled/enabled
timers/hrtimer: Use lockdep to assert IRQs are disabled/enabled
timers/nohz: Use lockdep to assert IRQs are disabled/enabled
workqueue: Use lockdep to assert IRQs are disabled/enabled
irq/softirqs: Use lockdep to assert IRQs are disabled/enabled
locking/lockdep: Add IRQs disabled/enabled assertion APIs: lockdep_assert_irqs_enabled()/disabled()
locking/pvqspinlock: Implement hybrid PV queued/unfair locks
locking/rwlocks: Fix comments
x86/paravirt: Set up the virt_spin_lock_key after static keys get initialized
block, locking/lockdep: Assign a lock_class per gendisk used for wait_for_completion()
workqueue: Remove now redundant lock acquisitions wrt. workqueue flushes
...
This commit is contained in:
commit
8e9a2dba86
307 changed files with 1252 additions and 1672 deletions
|
|
@ -709,6 +709,9 @@
|
|||
It will be ignored when crashkernel=X,high is not used
|
||||
or memory reserved is below 4G.
|
||||
|
||||
crossrelease_fullstack
|
||||
[KNL] Allow to record full stack trace in cross-release
|
||||
|
||||
cryptomgr.notests
|
||||
[KNL] Disable crypto self-tests
|
||||
|
||||
|
|
|
|||
|
|
@ -826,9 +826,9 @@ If the filesystem may need to revalidate dcache entries, then
|
|||
*is* passed the dentry but does not have access to the `inode` or the
|
||||
`seq` number from the `nameidata`, so it needs to be extra careful
|
||||
when accessing fields in the dentry. This "extra care" typically
|
||||
involves using `ACCESS_ONCE()` or the newer [`READ_ONCE()`] to access
|
||||
fields, and verifying the result is not NULL before using it. This
|
||||
pattern can be see in `nfs_lookup_revalidate()`.
|
||||
involves using [`READ_ONCE()`] to access fields, and verifying the
|
||||
result is not NULL before using it. This pattern can be seen in
|
||||
`nfs_lookup_revalidate()`.
|
||||
|
||||
A pair of patterns
|
||||
------------------
|
||||
|
|
|
|||
|
|
@ -1880,18 +1880,6 @@ There are some more advanced barrier functions:
|
|||
See Documentation/atomic_{t,bitops}.txt for more information.
|
||||
|
||||
|
||||
(*) lockless_dereference();
|
||||
|
||||
This can be thought of as a pointer-fetch wrapper around the
|
||||
smp_read_barrier_depends() data-dependency barrier.
|
||||
|
||||
This is also similar to rcu_dereference(), but in cases where
|
||||
object lifetime is handled by some mechanism other than RCU, for
|
||||
example, when the objects removed only when the system goes down.
|
||||
In addition, lockless_dereference() is used in some data structures
|
||||
that can be used both with and without RCU.
|
||||
|
||||
|
||||
(*) dma_wmb();
|
||||
(*) dma_rmb();
|
||||
|
||||
|
|
|
|||
|
|
@ -1858,18 +1858,6 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
|
|||
참고하세요.
|
||||
|
||||
|
||||
(*) lockless_dereference();
|
||||
|
||||
이 함수는 smp_read_barrier_depends() 데이터 의존성 배리어를 사용하는
|
||||
포인터 읽어오기 래퍼(wrapper) 함수로 생각될 수 있습니다.
|
||||
|
||||
객체의 라이프타임이 RCU 외의 메커니즘으로 관리된다는 점을 제외하면
|
||||
rcu_dereference() 와도 유사한데, 예를 들면 객체가 시스템이 꺼질 때에만
|
||||
제거되는 경우 등입니다. 또한, lockless_dereference() 은 RCU 와 함께
|
||||
사용될수도, RCU 없이 사용될 수도 있는 일부 데이터 구조에 사용되고
|
||||
있습니다.
|
||||
|
||||
|
||||
(*) dma_wmb();
|
||||
(*) dma_rmb();
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,15 @@
|
|||
* than regular operations.
|
||||
*/
|
||||
|
||||
/*
|
||||
* To ensure dependency ordering is preserved for the _relaxed and
|
||||
* _release atomics, an smp_read_barrier_depends() is unconditionally
|
||||
* inserted into the _relaxed variants, which are used to build the
|
||||
* barriered versions. To avoid redundant back-to-back fences, we can
|
||||
* define the _acquire and _fence versions explicitly.
|
||||
*/
|
||||
#define __atomic_op_acquire(op, args...) op##_relaxed(args)
|
||||
#define __atomic_op_fence __atomic_op_release
|
||||
|
||||
#define ATOMIC_INIT(i) { (i) }
|
||||
#define ATOMIC64_INIT(i) { (i) }
|
||||
|
|
@ -61,6 +70,7 @@ static inline int atomic_##op##_return_relaxed(int i, atomic_t *v) \
|
|||
".previous" \
|
||||
:"=&r" (temp), "=m" (v->counter), "=&r" (result) \
|
||||
:"Ir" (i), "m" (v->counter) : "memory"); \
|
||||
smp_read_barrier_depends(); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +88,7 @@ static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v) \
|
|||
".previous" \
|
||||
:"=&r" (temp), "=m" (v->counter), "=&r" (result) \
|
||||
:"Ir" (i), "m" (v->counter) : "memory"); \
|
||||
smp_read_barrier_depends(); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +123,7 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \
|
|||
".previous" \
|
||||
:"=&r" (temp), "=m" (v->counter), "=&r" (result) \
|
||||
:"Ir" (i), "m" (v->counter) : "memory"); \
|
||||
smp_read_barrier_depends(); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
|
|
@ -129,6 +141,7 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \
|
|||
".previous" \
|
||||
:"=&r" (temp), "=m" (v->counter), "=&r" (result) \
|
||||
:"Ir" (i), "m" (v->counter) : "memory"); \
|
||||
smp_read_barrier_depends(); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
|
||||
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
|
||||
|
||||
static inline void __down_read(struct rw_semaphore *sem)
|
||||
static inline int ___down_read(struct rw_semaphore *sem)
|
||||
{
|
||||
long oldcount;
|
||||
#ifndef CONFIG_SMP
|
||||
|
|
@ -42,10 +42,24 @@ static inline void __down_read(struct rw_semaphore *sem)
|
|||
:"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
|
||||
:"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
|
||||
#endif
|
||||
if (unlikely(oldcount < 0))
|
||||
return (oldcount < 0);
|
||||
}
|
||||
|
||||
static inline void __down_read(struct rw_semaphore *sem)
|
||||
{
|
||||
if (unlikely(___down_read(sem)))
|
||||
rwsem_down_read_failed(sem);
|
||||
}
|
||||
|
||||
static inline int __down_read_killable(struct rw_semaphore *sem)
|
||||
{
|
||||
if (unlikely(___down_read(sem)))
|
||||
if (IS_ERR(rwsem_down_read_failed_killable(sem)))
|
||||
return -EINTR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* trylock for reading -- returns 1 if successful, 0 if contention
|
||||
*/
|
||||
|
|
@ -95,9 +109,10 @@ static inline void __down_write(struct rw_semaphore *sem)
|
|||
|
||||
static inline int __down_write_killable(struct rw_semaphore *sem)
|
||||
{
|
||||
if (unlikely(___down_write(sem)))
|
||||
if (unlikely(___down_write(sem))) {
|
||||
if (IS_ERR(rwsem_down_write_failed_killable(sem)))
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
* We make no fairness assumptions. They have a cost.
|
||||
*/
|
||||
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
#define arch_spin_is_locked(x) ((x)->lock != 0)
|
||||
|
||||
static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
|
||||
|
|
@ -55,16 +54,6 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
|
|||
|
||||
/***********************************************************/
|
||||
|
||||
static inline int arch_read_can_lock(arch_rwlock_t *lock)
|
||||
{
|
||||
return (lock->lock & 1) == 0;
|
||||
}
|
||||
|
||||
static inline int arch_write_can_lock(arch_rwlock_t *lock)
|
||||
{
|
||||
return lock->lock == 0;
|
||||
}
|
||||
|
||||
static inline void arch_read_lock(arch_rwlock_t *lock)
|
||||
{
|
||||
long regx;
|
||||
|
|
@ -171,7 +160,4 @@ static inline void arch_write_unlock(arch_rwlock_t * lock)
|
|||
lock->lock = 0;
|
||||
}
|
||||
|
||||
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
|
||||
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
|
||||
|
||||
#endif /* _ALPHA_SPINLOCK_H */
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <asm/barrier.h>
|
||||
|
||||
#define arch_spin_is_locked(x) ((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__)
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
|
||||
#ifdef CONFIG_ARC_HAS_LLSC
|
||||
|
||||
|
|
@ -410,14 +409,4 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
|
|||
|
||||
#endif
|
||||
|
||||
#define arch_read_can_lock(x) ((x)->counter > 0)
|
||||
#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
|
||||
|
||||
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
|
||||
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
|
||||
|
||||
#define arch_spin_relax(lock) cpu_relax()
|
||||
#define arch_read_relax(lock) cpu_relax()
|
||||
#define arch_write_relax(lock) cpu_relax()
|
||||
|
||||
#endif /* __ASM_SPINLOCK_H */
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ static void ipi_send_msg_one(int cpu, enum ipi_msg_type msg)
|
|||
* and read back old value
|
||||
*/
|
||||
do {
|
||||
new = old = ACCESS_ONCE(*ipi_data_ptr);
|
||||
new = old = READ_ONCE(*ipi_data_ptr);
|
||||
new |= 1U << msg;
|
||||
} while (cmpxchg(ipi_data_ptr, old, new) != old);
|
||||
|
||||
|
|
|
|||
|
|
@ -126,8 +126,7 @@ extern unsigned long profile_pc(struct pt_regs *regs);
|
|||
/*
|
||||
* kprobe-based event tracer support
|
||||
*/
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/compiler.h>
|
||||
#define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0))
|
||||
|
||||
extern int regs_query_register_offset(const char *name);
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ static inline void dsb_sev(void)
|
|||
* memory.
|
||||
*/
|
||||
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
|
||||
static inline void arch_spin_lock(arch_spinlock_t *lock)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
|
@ -74,7 +72,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
|
|||
|
||||
while (lockval.tickets.next != lockval.tickets.owner) {
|
||||
wfe();
|
||||
lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);
|
||||
lockval.tickets.owner = READ_ONCE(lock->tickets.owner);
|
||||
}
|
||||
|
||||
smp_mb();
|
||||
|
|
@ -194,9 +192,6 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
|
|||
dsb_sev();
|
||||
}
|
||||
|
||||
/* write_can_lock - would write_trylock() succeed? */
|
||||
#define arch_write_can_lock(x) (ACCESS_ONCE((x)->lock) == 0)
|
||||
|
||||
/*
|
||||
* Read locks are a bit more hairy:
|
||||
* - Exclusively load the lock value.
|
||||
|
|
@ -274,14 +269,4 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
|
|||
}
|
||||
}
|
||||
|
||||
/* read_can_lock - would read_trylock() succeed? */
|
||||
#define arch_read_can_lock(x) (ACCESS_ONCE((x)->lock) < 0x80000000)
|
||||
|
||||
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
|
||||
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
|
||||
|
||||
#define arch_spin_relax(lock) cpu_relax()
|
||||
#define arch_read_relax(lock) cpu_relax()
|
||||
#define arch_write_relax(lock) cpu_relax()
|
||||
|
||||
#endif /* __ASM_SPINLOCK_H */
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
|
|||
bool entered_lp2 = false;
|
||||
|
||||
if (tegra_pending_sgi())
|
||||
ACCESS_ONCE(abort_flag) = true;
|
||||
WRITE_ONCE(abort_flag, true);
|
||||
|
||||
cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ static notrace u32 __vdso_read_begin(const struct vdso_data *vdata)
|
|||
{
|
||||
u32 seq;
|
||||
repeat:
|
||||
seq = ACCESS_ONCE(vdata->seq_count);
|
||||
seq = READ_ONCE(vdata->seq_count);
|
||||
if (seq & 1) {
|
||||
cpu_relax();
|
||||
goto repeat;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,24 @@ config ARM64
|
|||
select ARCH_HAS_STRICT_MODULE_RWX
|
||||
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select ARCH_HAVE_NMI_SAFE_CMPXCHG if ACPI_APEI_SEA
|
||||
select ARCH_INLINE_READ_LOCK if !PREEMPT
|
||||
select ARCH_INLINE_READ_LOCK_BH if !PREEMPT
|
||||
select ARCH_INLINE_READ_LOCK_IRQ if !PREEMPT
|
||||
select ARCH_INLINE_READ_LOCK_IRQSAVE if !PREEMPT
|
||||
select ARCH_INLINE_READ_UNLOCK if !PREEMPT
|
||||
select ARCH_INLINE_READ_UNLOCK_BH if !PREEMPT
|
||||
select ARCH_INLINE_READ_UNLOCK_IRQ if !PREEMPT
|
||||
select ARCH_INLINE_READ_UNLOCK_IRQRESTORE if !PREEMPT
|
||||
select ARCH_INLINE_WRITE_LOCK if !PREEMPT
|
||||
select ARCH_INLINE_WRITE_LOCK_BH if !PREEMPT
|
||||
select ARCH_INLINE_WRITE_LOCK_IRQ if !PREEMPT
|
||||
select ARCH_INLINE_WRITE_LOCK_IRQSAVE if !PREEMPT
|
||||
select ARCH_INLINE_WRITE_UNLOCK if !PREEMPT
|
||||
select ARCH_INLINE_WRITE_UNLOCK_BH if !PREEMPT
|
||||
select ARCH_INLINE_WRITE_UNLOCK_IRQ if !PREEMPT
|
||||
select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE if !PREEMPT
|
||||
select ARCH_USE_CMPXCHG_LOCKREF
|
||||
select ARCH_USE_QUEUED_RWLOCKS
|
||||
select ARCH_SUPPORTS_MEMORY_FAILURE
|
||||
select ARCH_SUPPORTS_ATOMIC_RMW
|
||||
select ARCH_SUPPORTS_NUMA_BALANCING
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ generic-y += mcs_spinlock.h
|
|||
generic-y += mm-arch-hooks.h
|
||||
generic-y += msi.h
|
||||
generic-y += preempt.h
|
||||
generic-y += qrwlock.h
|
||||
generic-y += rwsem.h
|
||||
generic-y += segment.h
|
||||
generic-y += serial.h
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@
|
|||
* instructions.
|
||||
*/
|
||||
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
|
||||
static inline void arch_spin_lock(arch_spinlock_t *lock)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
|
@ -139,176 +137,7 @@ static inline int arch_spin_is_contended(arch_spinlock_t *lock)
|
|||
}
|
||||
#define arch_spin_is_contended arch_spin_is_contended
|
||||
|
||||
/*
|
||||
* Write lock implementation.
|
||||
*
|
||||
* Write locks set bit 31. Unlocking, is done by writing 0 since the lock is
|
||||
* exclusively held.
|
||||
*
|
||||
* The memory barriers are implicit with the load-acquire and store-release
|
||||
* instructions.
|
||||
*/
|
||||
|
||||
static inline void arch_write_lock(arch_rwlock_t *rw)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
asm volatile(ARM64_LSE_ATOMIC_INSN(
|
||||
/* LL/SC */
|
||||
" sevl\n"
|
||||
"1: wfe\n"
|
||||
"2: ldaxr %w0, %1\n"
|
||||
" cbnz %w0, 1b\n"
|
||||
" stxr %w0, %w2, %1\n"
|
||||
" cbnz %w0, 2b\n"
|
||||
__nops(1),
|
||||
/* LSE atomics */
|
||||
"1: mov %w0, wzr\n"
|
||||
"2: casa %w0, %w2, %1\n"
|
||||
" cbz %w0, 3f\n"
|
||||
" ldxr %w0, %1\n"
|
||||
" cbz %w0, 2b\n"
|
||||
" wfe\n"
|
||||
" b 1b\n"
|
||||
"3:")
|
||||
: "=&r" (tmp), "+Q" (rw->lock)
|
||||
: "r" (0x80000000)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline int arch_write_trylock(arch_rwlock_t *rw)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
asm volatile(ARM64_LSE_ATOMIC_INSN(
|
||||
/* LL/SC */
|
||||
"1: ldaxr %w0, %1\n"
|
||||
" cbnz %w0, 2f\n"
|
||||
" stxr %w0, %w2, %1\n"
|
||||
" cbnz %w0, 1b\n"
|
||||
"2:",
|
||||
/* LSE atomics */
|
||||
" mov %w0, wzr\n"
|
||||
" casa %w0, %w2, %1\n"
|
||||
__nops(2))
|
||||
: "=&r" (tmp), "+Q" (rw->lock)
|
||||
: "r" (0x80000000)
|
||||
: "memory");
|
||||
|
||||
return !tmp;
|
||||
}
|
||||
|
||||
static inline void arch_write_unlock(arch_rwlock_t *rw)
|
||||
{
|
||||
asm volatile(ARM64_LSE_ATOMIC_INSN(
|
||||
" stlr wzr, %0",
|
||||
" swpl wzr, wzr, %0")
|
||||
: "=Q" (rw->lock) :: "memory");
|
||||
}
|
||||
|
||||
/* write_can_lock - would write_trylock() succeed? */
|
||||
#define arch_write_can_lock(x) ((x)->lock == 0)
|
||||
|
||||
/*
|
||||
* Read lock implementation.
|
||||
*
|
||||
* It exclusively loads the lock value, increments it and stores the new value
|
||||
* back if positive and the CPU still exclusively owns the location. If the
|
||||
* value is negative, the lock is already held.
|
||||
*
|
||||
* During unlocking there may be multiple active read locks but no write lock.
|
||||
*
|
||||
* The memory barriers are implicit with the load-acquire and store-release
|
||||
* instructions.
|
||||
*
|
||||
* Note that in UNDEFINED cases, such as unlocking a lock twice, the LL/SC
|
||||
* and LSE implementations may exhibit different behaviour (although this
|
||||
* will have no effect on lockdep).
|
||||
*/
|
||||
static inline void arch_read_lock(arch_rwlock_t *rw)
|
||||
{
|
||||
unsigned int tmp, tmp2;
|
||||
|
||||
asm volatile(
|
||||
" sevl\n"
|
||||
ARM64_LSE_ATOMIC_INSN(
|
||||
/* LL/SC */
|
||||
"1: wfe\n"
|
||||
"2: ldaxr %w0, %2\n"
|
||||
" add %w0, %w0, #1\n"
|
||||
" tbnz %w0, #31, 1b\n"
|
||||
" stxr %w1, %w0, %2\n"
|
||||
" cbnz %w1, 2b\n"
|
||||
__nops(1),
|
||||
/* LSE atomics */
|
||||
"1: wfe\n"
|
||||
"2: ldxr %w0, %2\n"
|
||||
" adds %w1, %w0, #1\n"
|
||||
" tbnz %w1, #31, 1b\n"
|
||||
" casa %w0, %w1, %2\n"
|
||||
" sbc %w0, %w1, %w0\n"
|
||||
" cbnz %w0, 2b")
|
||||
: "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
|
||||
:
|
||||
: "cc", "memory");
|
||||
}
|
||||
|
||||
static inline void arch_read_unlock(arch_rwlock_t *rw)
|
||||
{
|
||||
unsigned int tmp, tmp2;
|
||||
|
||||
asm volatile(ARM64_LSE_ATOMIC_INSN(
|
||||
/* LL/SC */
|
||||
"1: ldxr %w0, %2\n"
|
||||
" sub %w0, %w0, #1\n"
|
||||
" stlxr %w1, %w0, %2\n"
|
||||
" cbnz %w1, 1b",
|
||||
/* LSE atomics */
|
||||
" movn %w0, #0\n"
|
||||
" staddl %w0, %2\n"
|
||||
__nops(2))
|
||||
: "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
|
||||
:
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline int arch_read_trylock(arch_rwlock_t *rw)
|
||||
{
|
||||
unsigned int tmp, tmp2;
|
||||
|
||||
asm volatile(ARM64_LSE_ATOMIC_INSN(
|
||||
/* LL/SC */
|
||||
" mov %w1, #1\n"
|
||||
"1: ldaxr %w0, %2\n"
|
||||
" add %w0, %w0, #1\n"
|
||||
" tbnz %w0, #31, 2f\n"
|
||||
" stxr %w1, %w0, %2\n"
|
||||
" cbnz %w1, 1b\n"
|
||||
"2:",
|
||||
/* LSE atomics */
|
||||
" ldr %w0, %2\n"
|
||||
" adds %w1, %w0, #1\n"
|
||||
" tbnz %w1, #31, 1f\n"
|
||||
" casa %w0, %w1, %2\n"
|
||||
" sbc %w1, %w1, %w0\n"
|
||||
__nops(1)
|
||||
"1:")
|
||||
: "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
|
||||
:
|
||||
: "cc", "memory");
|
||||
|
||||
return !tmp2;
|
||||
}
|
||||
|
||||
/* read_can_lock - would read_trylock() succeed? */
|
||||
#define arch_read_can_lock(x) ((x)->lock < 0x80000000)
|
||||
|
||||
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
|
||||
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
|
||||
|
||||
#define arch_spin_relax(lock) cpu_relax()
|
||||
#define arch_read_relax(lock) cpu_relax()
|
||||
#define arch_write_relax(lock) cpu_relax()
|
||||
#include <asm/qrwlock.h>
|
||||
|
||||
/* See include/linux/spinlock.h */
|
||||
#define smp_mb__after_spinlock() smp_mb()
|
||||
|
|
|
|||
|
|
@ -36,10 +36,6 @@ typedef struct {
|
|||
|
||||
#define __ARCH_SPIN_LOCK_UNLOCKED { 0 , 0 }
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned int lock;
|
||||
} arch_rwlock_t;
|
||||
|
||||
#define __ARCH_RW_LOCK_UNLOCKED { 0 }
|
||||
#include <asm-generic/qrwlock_types.h>
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,8 +36,6 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
|
|||
__raw_spin_lock_asm(&lock->lock);
|
||||
}
|
||||
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
|
||||
static inline int arch_spin_trylock(arch_spinlock_t *lock)
|
||||
{
|
||||
return __raw_spin_trylock_asm(&lock->lock);
|
||||
|
|
@ -48,23 +46,11 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
|
|||
__raw_spin_unlock_asm(&lock->lock);
|
||||
}
|
||||
|
||||
static inline int arch_read_can_lock(arch_rwlock_t *rw)
|
||||
{
|
||||
return __raw_uncached_fetch_asm(&rw->lock) > 0;
|
||||
}
|
||||
|
||||
static inline int arch_write_can_lock(arch_rwlock_t *rw)
|
||||
{
|
||||
return __raw_uncached_fetch_asm(&rw->lock) == RW_LOCK_BIAS;
|
||||
}
|
||||
|
||||
static inline void arch_read_lock(arch_rwlock_t *rw)
|
||||
{
|
||||
__raw_read_lock_asm(&rw->lock);
|
||||
}
|
||||
|
||||
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
|
||||
|
||||
static inline int arch_read_trylock(arch_rwlock_t *rw)
|
||||
{
|
||||
return __raw_read_trylock_asm(&rw->lock);
|
||||
|
|
@ -80,8 +66,6 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
|
|||
__raw_write_lock_asm(&rw->lock);
|
||||
}
|
||||
|
||||
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
|
||||
|
||||
static inline int arch_write_trylock(arch_rwlock_t *rw)
|
||||
{
|
||||
return __raw_write_trylock_asm(&rw->lock);
|
||||
|
|
@ -92,10 +76,6 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
|
|||
__raw_write_unlock_asm(&rw->lock);
|
||||
}
|
||||
|
||||
#define arch_spin_relax(lock) cpu_relax()
|
||||
#define arch_read_relax(lock) cpu_relax()
|
||||
#define arch_write_relax(lock) cpu_relax()
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !__BFIN_SPINLOCK_H */
|
||||
|
|
|
|||
|
|
@ -86,16 +86,6 @@ static inline int arch_read_trylock(arch_rwlock_t *lock)
|
|||
return temp;
|
||||
}
|
||||
|
||||
static inline int arch_read_can_lock(arch_rwlock_t *rwlock)
|
||||
{
|
||||
return rwlock->lock == 0;
|
||||
}
|
||||
|
||||
static inline int arch_write_can_lock(arch_rwlock_t *rwlock)
|
||||
{
|
||||
return rwlock->lock == 0;
|
||||
}
|
||||
|
||||
/* Stuffs a -1 in the lock value? */
|
||||
static inline void arch_write_lock(arch_rwlock_t *lock)
|
||||
{
|
||||
|
|
@ -177,11 +167,6 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
|
|||
/*
|
||||
* SMP spinlocks are intended to allow only a single CPU at the lock
|
||||
*/
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
|
||||
#define arch_spin_is_locked(x) ((x)->lock != 0)
|
||||
|
||||
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
|
||||
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -38,15 +38,31 @@
|
|||
/*
|
||||
* lock for reading
|
||||
*/
|
||||
static inline void
|
||||
__down_read (struct rw_semaphore *sem)
|
||||
static inline int
|
||||
___down_read (struct rw_semaphore *sem)
|
||||
{
|
||||
long result = ia64_fetchadd8_acq((unsigned long *)&sem->count.counter, 1);
|
||||
|
||||
if (result < 0)
|
||||
return (result < 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
__down_read (struct rw_semaphore *sem)
|
||||
{
|
||||
if (___down_read(sem))
|
||||
rwsem_down_read_failed(sem);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__down_read_killable (struct rw_semaphore *sem)
|
||||
{
|
||||
if (___down_read(sem))
|
||||
if (IS_ERR(rwsem_down_read_failed_killable(sem)))
|
||||
return -EINTR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* lock for writing
|
||||
*/
|
||||
|
|
@ -73,9 +89,10 @@ __down_write (struct rw_semaphore *sem)
|
|||
static inline int
|
||||
__down_write_killable (struct rw_semaphore *sem)
|
||||
{
|
||||
if (___down_write(sem))
|
||||
if (___down_write(sem)) {
|
||||
if (IS_ERR(rwsem_down_write_failed_killable(sem)))
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue