diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 20:59:54 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 20:59:54 +0300 |
commit | 568d135d337d3114688fef9fdbce7fb6dbbd04c7 (patch) | |
tree | b9355b94182a51eec5cfc69dd335e39a2e97ac7d /arch/mips/include/asm/spinlock.h | |
parent | 4ecd4ff55ac5c7fe9e232f34a41c4d54f2d825c1 (diff) | |
parent | d40e0d4fb5613099a58c95a9403f51b03e40e861 (diff) | |
download | linux-568d135d337d3114688fef9fdbce7fb6dbbd04c7.tar.xz |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
"Boston platform support:
- Document DT bindings
- Add CLK driver for board clocks
CM:
- Avoid per-core locking with CM3 & higher
- WARN on attempt to lock invalid VP, not BUG
CPS:
- Select CONFIG_SYS_SUPPORTS_SCHED_SMT for MIPSr6
- Prevent multi-core with dcache aliasing
- Handle cores not powering down more gracefully
- Handle spurious VP starts more gracefully
DSP:
- Add lwx & lhx missaligned access support
eBPF:
- Add MIPS support along with many supporting change to add the
required infrastructure
Generic arch code:
- Misc sysmips MIPS_ATOMIC_SET fixes
- Drop duplicate HAVE_SYSCALL_TRACEPOINTS
- Negate error syscall return in trace
- Correct forced syscall errors
- Traced negative syscalls should return -ENOSYS
- Allow samples/bpf/tracex5 to access syscall arguments for sane
traces
- Cleanup from old Kconfig options in defconfigs
- Fix PREF instruction usage by memcpy for MIPS R6
- Fix various special cases in the FPU eulation
- Fix some special cases in MIPS16e2 support
- Fix MIPS I ISA /proc/cpuinfo reporting
- Sort MIPS Kconfig alphabetically
- Fix minimum alignment requirement of IRQ stack as required by
ABI / GCC
- Fix special cases in the module loader
- Perform post-DMA cache flushes on systems with MAARs
- Probe the I6500 CPU
- Cleanup cmpxchg and add support for 1 and 2 byte operations
- Use queued read/write locks (qrwlock)
- Use queued spinlocks (qspinlock)
- Add CPU shared FTLB feature detection
- Handle tlbex-tlbp race condition
- Allow storing pgd in C0_CONTEXT for MIPSr6
- Use current_cpu_type() in m4kc_tlbp_war()
- Support Boston in the generic kernel
Generic platform:
- yamon-dt: Pull YAMON DT shim code out of SEAD-3 board
- yamon-dt: Support > 256MB of RAM
- yamon-dt: Use serial* rather than uart* aliases
- Abstract FDT fixup application
- Set RTC_ALWAYS_BCD to 0
- Add a MAINTAINERS entry
core kernel:
- qspinlock.c: include linux/prefetch.h
Loongson 3:
- Add support
Perf:
- Add I6500 support
SEAD-3:
- Remove GIC timer from DT
- Set interrupt-parent per-device, not at root node
- Fix GIC interrupt specifiers
SMP:
- Skip IPI setup if we only have a single CPU
VDSO:
- Make comment match reality
- Improvements to time code in VDSO"
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (86 commits)
locking/qspinlock: Include linux/prefetch.h
MIPS: Fix MIPS I ISA /proc/cpuinfo reporting
MIPS: Fix minimum alignment requirement of IRQ stack
MIPS: generic: Support MIPS Boston development boards
MIPS: DTS: img: Don't attempt to build-in all .dtb files
clk: boston: Add a driver for MIPS Boston board clocks
dt-bindings: Document img,boston-clock binding
MIPS: Traced negative syscalls should return -ENOSYS
MIPS: Correct forced syscall errors
MIPS: Negate error syscall return in trace
MIPS: Drop duplicate HAVE_SYSCALL_TRACEPOINTS select
MIPS16e2: Provide feature overrides for non-MIPS16 systems
MIPS: MIPS16e2: Report ASE presence in /proc/cpuinfo
MIPS: MIPS16e2: Subdecode extended LWSP/SWSP instructions
MIPS: MIPS16e2: Identify ASE presence
MIPS: VDSO: Fix a mismatch between comment and preprocessor constant
MIPS: VDSO: Add implementation of gettimeofday() fallback
MIPS: VDSO: Add implementation of clock_gettime() fallback
MIPS: VDSO: Fix conversions in do_monotonic()/do_monotonic_coarse()
MIPS: Use current_cpu_type() in m4kc_tlbp_war()
...
Diffstat (limited to 'arch/mips/include/asm/spinlock.h')
-rw-r--r-- | arch/mips/include/asm/spinlock.h | 426 |
1 files changed, 2 insertions, 424 deletions
diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h index a8df44d60607..a7d21da16b6a 100644 --- a/arch/mips/include/asm/spinlock.h +++ b/arch/mips/include/asm/spinlock.h @@ -9,431 +9,9 @@ #ifndef _ASM_SPINLOCK_H #define _ASM_SPINLOCK_H -#include <linux/compiler.h> - -#include <asm/barrier.h> #include <asm/processor.h> -#include <asm/compiler.h> -#include <asm/war.h> - -/* - * Your basic SMP spinlocks, allowing only a single CPU anywhere - * - * Simple spin lock operations. There are two variants, one clears IRQ's - * on the local processor, one does not. - * - * These are fair FIFO ticket locks - * - * (the type definitions are in asm/spinlock_types.h) - */ - - -/* - * Ticket locks are conceptually two parts, one indicating the current head of - * the queue, and the other indicating the current tail. The lock is acquired - * by atomically noting the tail and incrementing it by one (thus adding - * ourself to the queue and noting our position), then waiting until the head - * becomes equal to the the initial value of the tail. - */ - -static inline int arch_spin_is_locked(arch_spinlock_t *lock) -{ - u32 counters = ACCESS_ONCE(lock->lock); - - return ((counters >> 16) ^ counters) & 0xffff; -} - -static inline int arch_spin_value_unlocked(arch_spinlock_t lock) -{ - return lock.h.serving_now == lock.h.ticket; -} - -#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) - -static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) -{ - u16 owner = READ_ONCE(lock->h.serving_now); - smp_rmb(); - for (;;) { - arch_spinlock_t tmp = READ_ONCE(*lock); - - if (tmp.h.serving_now == tmp.h.ticket || - tmp.h.serving_now != owner) - break; - - cpu_relax(); - } - smp_acquire__after_ctrl_dep(); -} - -static inline int arch_spin_is_contended(arch_spinlock_t *lock) -{ - u32 counters = ACCESS_ONCE(lock->lock); - - return (((counters >> 16) - counters) & 0xffff) > 1; -} -#define arch_spin_is_contended arch_spin_is_contended - -static inline void arch_spin_lock(arch_spinlock_t *lock) -{ - int my_ticket; - int tmp; - int inc = 0x10000; - - if (R10000_LLSC_WAR) { - __asm__ __volatile__ ( - " .set push # arch_spin_lock \n" - " .set noreorder \n" - " \n" - "1: ll %[ticket], %[ticket_ptr] \n" - " addu %[my_ticket], %[ticket], %[inc] \n" - " sc %[my_ticket], %[ticket_ptr] \n" - " beqzl %[my_ticket], 1b \n" - " nop \n" - " srl %[my_ticket], %[ticket], 16 \n" - " andi %[ticket], %[ticket], 0xffff \n" - " bne %[ticket], %[my_ticket], 4f \n" - " subu %[ticket], %[my_ticket], %[ticket] \n" - "2: \n" - " .subsection 2 \n" - "4: andi %[ticket], %[ticket], 0xffff \n" - " sll %[ticket], 5 \n" - " \n" - "6: bnez %[ticket], 6b \n" - " subu %[ticket], 1 \n" - " \n" - " lhu %[ticket], %[serving_now_ptr] \n" - " beq %[ticket], %[my_ticket], 2b \n" - " subu %[ticket], %[my_ticket], %[ticket] \n" - " b 4b \n" - " subu %[ticket], %[ticket], 1 \n" - " .previous \n" - " .set pop \n" - : [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock), - [serving_now_ptr] "+m" (lock->h.serving_now), - [ticket] "=&r" (tmp), - [my_ticket] "=&r" (my_ticket) - : [inc] "r" (inc)); - } else { - __asm__ __volatile__ ( - " .set push # arch_spin_lock \n" - " .set noreorder \n" - " \n" - "1: ll %[ticket], %[ticket_ptr] \n" - " addu %[my_ticket], %[ticket], %[inc] \n" - " sc %[my_ticket], %[ticket_ptr] \n" - " beqz %[my_ticket], 1b \n" - " srl %[my_ticket], %[ticket], 16 \n" - " andi %[ticket], %[ticket], 0xffff \n" - " bne %[ticket], %[my_ticket], 4f \n" - " subu %[ticket], %[my_ticket], %[ticket] \n" - "2: .insn \n" - " .subsection 2 \n" - "4: andi %[ticket], %[ticket], 0xffff \n" - " sll %[ticket], 5 \n" - " \n" - "6: bnez %[ticket], 6b \n" - " subu %[ticket], 1 \n" - " \n" - " lhu %[ticket], %[serving_now_ptr] \n" - " beq %[ticket], %[my_ticket], 2b \n" - " subu %[ticket], %[my_ticket], %[ticket] \n" - " b 4b \n" - " subu %[ticket], %[ticket], 1 \n" - " .previous \n" - " .set pop \n" - : [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock), - [serving_now_ptr] "+m" (lock->h.serving_now), - [ticket] "=&r" (tmp), - [my_ticket] "=&r" (my_ticket) - : [inc] "r" (inc)); - } - - smp_llsc_mb(); -} - -static inline void arch_spin_unlock(arch_spinlock_t *lock) -{ - unsigned int serving_now = lock->h.serving_now + 1; - wmb(); - lock->h.serving_now = (u16)serving_now; - nudge_writes(); -} - -static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock) -{ - int tmp, tmp2, tmp3; - int inc = 0x10000; - - if (R10000_LLSC_WAR) { - __asm__ __volatile__ ( - " .set push # arch_spin_trylock \n" - " .set noreorder \n" - " \n" - "1: ll %[ticket], %[ticket_ptr] \n" - " srl %[my_ticket], %[ticket], 16 \n" - " andi %[now_serving], %[ticket], 0xffff \n" - " bne %[my_ticket], %[now_serving], 3f \n" - " addu %[ticket], %[ticket], %[inc] \n" - " sc %[ticket], %[ticket_ptr] \n" - " beqzl %[ticket], 1b \n" - " li %[ticket], 1 \n" - "2: \n" - " .subsection 2 \n" - "3: b 2b \n" - " li %[ticket], 0 \n" - " .previous \n" - " .set pop \n" - : [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock), - [ticket] "=&r" (tmp), - [my_ticket] "=&r" (tmp2), - [now_serving] "=&r" (tmp3) - : [inc] "r" (inc)); - } else { - __asm__ __volatile__ ( - " .set push # arch_spin_trylock \n" - " .set noreorder \n" - " \n" - "1: ll %[ticket], %[ticket_ptr] \n" - " srl %[my_ticket], %[ticket], 16 \n" - " andi %[now_serving], %[ticket], 0xffff \n" - " bne %[my_ticket], %[now_serving], 3f \n" - " addu %[ticket], %[ticket], %[inc] \n" - " sc %[ticket], %[ticket_ptr] \n" - " beqz %[ticket], 1b \n" - " li %[ticket], 1 \n" - "2: .insn \n" - " .subsection 2 \n" - "3: b 2b \n" - " li %[ticket], 0 \n" - " .previous \n" - " .set pop \n" - : [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock), - [ticket] "=&r" (tmp), - [my_ticket] "=&r" (tmp2), - [now_serving] "=&r" (tmp3) - : [inc] "r" (inc)); - } - - smp_llsc_mb(); - - return tmp; -} - -/* - * Read-write spinlocks, allowing multiple readers but only one writer. - * - * NOTE! it is quite common to have readers in interrupts but no interrupt - * writers. For those circumstances we can "mix" irq-safe locks - any writer - * needs to get a irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - */ - -/* - * read_can_lock - would read_trylock() succeed? - * @lock: the rwlock in question. - */ -#define arch_read_can_lock(rw) ((rw)->lock >= 0) - -/* - * write_can_lock - would write_trylock() succeed? - * @lock: the rwlock in question. - */ -#define arch_write_can_lock(rw) (!(rw)->lock) - -static inline void arch_read_lock(arch_rwlock_t *rw) -{ - unsigned int tmp; - - if (R10000_LLSC_WAR) { - __asm__ __volatile__( - " .set noreorder # arch_read_lock \n" - "1: ll %1, %2 \n" - " bltz %1, 1b \n" - " addu %1, 1 \n" - " sc %1, %0 \n" - " beqzl %1, 1b \n" - " nop \n" - " .set reorder \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } else { - do { - __asm__ __volatile__( - "1: ll %1, %2 # arch_read_lock \n" - " bltz %1, 1b \n" - " addu %1, 1 \n" - "2: sc %1, %0 \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } while (unlikely(!tmp)); - } - - smp_llsc_mb(); -} - -static inline void arch_read_unlock(arch_rwlock_t *rw) -{ - unsigned int tmp; - - smp_mb__before_llsc(); - - if (R10000_LLSC_WAR) { - __asm__ __volatile__( - "1: ll %1, %2 # arch_read_unlock \n" - " addiu %1, -1 \n" - " sc %1, %0 \n" - " beqzl %1, 1b \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } else { - do { - __asm__ __volatile__( - "1: ll %1, %2 # arch_read_unlock \n" - " addiu %1, -1 \n" - " sc %1, %0 \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } while (unlikely(!tmp)); - } -} - -static inline void arch_write_lock(arch_rwlock_t *rw) -{ - unsigned int tmp; - - if (R10000_LLSC_WAR) { - __asm__ __volatile__( - " .set noreorder # arch_write_lock \n" - "1: ll %1, %2 \n" - " bnez %1, 1b \n" - " lui %1, 0x8000 \n" - " sc %1, %0 \n" - " beqzl %1, 1b \n" - " nop \n" - " .set reorder \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } else { - do { - __asm__ __volatile__( - "1: ll %1, %2 # arch_write_lock \n" - " bnez %1, 1b \n" - " lui %1, 0x8000 \n" - "2: sc %1, %0 \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } while (unlikely(!tmp)); - } - - smp_llsc_mb(); -} - -static inline void arch_write_unlock(arch_rwlock_t *rw) -{ - smp_mb__before_llsc(); - - __asm__ __volatile__( - " # arch_write_unlock \n" - " sw $0, %0 \n" - : "=m" (rw->lock) - : "m" (rw->lock) - : "memory"); -} - -static inline int arch_read_trylock(arch_rwlock_t *rw) -{ - unsigned int tmp; - int ret; - - if (R10000_LLSC_WAR) { - __asm__ __volatile__( - " .set noreorder # arch_read_trylock \n" - " li %2, 0 \n" - "1: ll %1, %3 \n" - " bltz %1, 2f \n" - " addu %1, 1 \n" - " sc %1, %0 \n" - " .set reorder \n" - " beqzl %1, 1b \n" - " nop \n" - __WEAK_LLSC_MB - " li %2, 1 \n" - "2: \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } else { - __asm__ __volatile__( - " .set noreorder # arch_read_trylock \n" - " li %2, 0 \n" - "1: ll %1, %3 \n" - " bltz %1, 2f \n" - " addu %1, 1 \n" - " sc %1, %0 \n" - " beqz %1, 1b \n" - " nop \n" - " .set reorder \n" - __WEAK_LLSC_MB - " li %2, 1 \n" - "2: .insn \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } - - return ret; -} - -static inline int arch_write_trylock(arch_rwlock_t *rw) -{ - unsigned int tmp; - int ret; - - if (R10000_LLSC_WAR) { - __asm__ __volatile__( - " .set noreorder # arch_write_trylock \n" - " li %2, 0 \n" - "1: ll %1, %3 \n" - " bnez %1, 2f \n" - " lui %1, 0x8000 \n" - " sc %1, %0 \n" - " beqzl %1, 1b \n" - " nop \n" - __WEAK_LLSC_MB - " li %2, 1 \n" - " .set reorder \n" - "2: \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } else { - do { - __asm__ __volatile__( - " ll %1, %3 # arch_write_trylock \n" - " li %2, 0 \n" - " bnez %1, 2f \n" - " lui %1, 0x8000 \n" - " sc %1, %0 \n" - " li %2, 1 \n" - "2: .insn \n" - : "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), - "=&r" (ret) - : GCC_OFF_SMALL_ASM() (rw->lock) - : "memory"); - } while (unlikely(!tmp)); - - smp_llsc_mb(); - } - - return ret; -} +#include <asm/qrwlock.h> +#include <asm/qspinlock.h> #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) |