mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
sh: add J2 atomics using the cas.l instruction
Signed-off-by: Rich Felker <dalias@libc.org>
This commit is contained in:
parent
834da19705
commit
2b47d54ed4
9 changed files with 481 additions and 216 deletions
|
@ -1,6 +1,12 @@
|
||||||
#ifndef __ASM_SH_ATOMIC_H
|
#ifndef __ASM_SH_ATOMIC_H
|
||||||
#define __ASM_SH_ATOMIC_H
|
#define __ASM_SH_ATOMIC_H
|
||||||
|
|
||||||
|
#if defined(CONFIG_CPU_J2)
|
||||||
|
|
||||||
|
#include <asm-generic/atomic.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Atomic operations that C can't guarantee us. Useful for
|
* Atomic operations that C can't guarantee us. Useful for
|
||||||
* resource counting etc..
|
* resource counting etc..
|
||||||
|
@ -63,4 +69,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_CPU_J2 */
|
||||||
|
|
||||||
#endif /* __ASM_SH_ATOMIC_H */
|
#endif /* __ASM_SH_ATOMIC_H */
|
||||||
|
|
|
@ -29,6 +29,11 @@
|
||||||
#define wmb() mb()
|
#define wmb() mb()
|
||||||
#define ctrl_barrier() __icbi(PAGE_OFFSET)
|
#define ctrl_barrier() __icbi(PAGE_OFFSET)
|
||||||
#else
|
#else
|
||||||
|
#if defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
|
||||||
|
#define __smp_mb() do { int tmp = 0; __asm__ __volatile__ ("cas.l %0,%0,@%1" : "+r"(tmp) : "z"(&tmp) : "memory", "t"); } while(0)
|
||||||
|
#define __smp_rmb() __smp_mb()
|
||||||
|
#define __smp_wmb() __smp_mb()
|
||||||
|
#endif
|
||||||
#define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
|
#define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
93
arch/sh/include/asm/bitops-cas.h
Normal file
93
arch/sh/include/asm/bitops-cas.h
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
#ifndef __ASM_SH_BITOPS_CAS_H
|
||||||
|
#define __ASM_SH_BITOPS_CAS_H
|
||||||
|
|
||||||
|
static inline unsigned __bo_cas(volatile unsigned *p, unsigned old, unsigned new)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("cas.l %1,%0,@r0"
|
||||||
|
: "+r"(new)
|
||||||
|
: "r"(old), "z"(p)
|
||||||
|
: "t", "memory" );
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_bit(int nr, volatile void *addr)
|
||||||
|
{
|
||||||
|
unsigned mask, old;
|
||||||
|
volatile unsigned *a = addr;
|
||||||
|
|
||||||
|
a += nr >> 5;
|
||||||
|
mask = 1U << (nr & 0x1f);
|
||||||
|
|
||||||
|
do old = *a;
|
||||||
|
while (__bo_cas(a, old, old|mask) != old);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void clear_bit(int nr, volatile void *addr)
|
||||||
|
{
|
||||||
|
unsigned mask, old;
|
||||||
|
volatile unsigned *a = addr;
|
||||||
|
|
||||||
|
a += nr >> 5;
|
||||||
|
mask = 1U << (nr & 0x1f);
|
||||||
|
|
||||||
|
do old = *a;
|
||||||
|
while (__bo_cas(a, old, old&~mask) != old);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void change_bit(int nr, volatile void *addr)
|
||||||
|
{
|
||||||
|
unsigned mask, old;
|
||||||
|
volatile unsigned *a = addr;
|
||||||
|
|
||||||
|
a += nr >> 5;
|
||||||
|
mask = 1U << (nr & 0x1f);
|
||||||
|
|
||||||
|
do old = *a;
|
||||||
|
while (__bo_cas(a, old, old^mask) != old);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int test_and_set_bit(int nr, volatile void *addr)
|
||||||
|
{
|
||||||
|
unsigned mask, old;
|
||||||
|
volatile unsigned *a = addr;
|
||||||
|
|
||||||
|
a += nr >> 5;
|
||||||
|
mask = 1U << (nr & 0x1f);
|
||||||
|
|
||||||
|
do old = *a;
|
||||||
|
while (__bo_cas(a, old, old|mask) != old);
|
||||||
|
|
||||||
|
return !!(old & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int test_and_clear_bit(int nr, volatile void *addr)
|
||||||
|
{
|
||||||
|
unsigned mask, old;
|
||||||
|
volatile unsigned *a = addr;
|
||||||
|
|
||||||
|
a += nr >> 5;
|
||||||
|
mask = 1U << (nr & 0x1f);
|
||||||
|
|
||||||
|
do old = *a;
|
||||||
|
while (__bo_cas(a, old, old&~mask) != old);
|
||||||
|
|
||||||
|
return !!(old & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int test_and_change_bit(int nr, volatile void *addr)
|
||||||
|
{
|
||||||
|
unsigned mask, old;
|
||||||
|
volatile unsigned *a = addr;
|
||||||
|
|
||||||
|
a += nr >> 5;
|
||||||
|
mask = 1U << (nr & 0x1f);
|
||||||
|
|
||||||
|
do old = *a;
|
||||||
|
while (__bo_cas(a, old, old^mask) != old);
|
||||||
|
|
||||||
|
return !!(old & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <asm-generic/bitops/non-atomic.h>
|
||||||
|
|
||||||
|
#endif /* __ASM_SH_BITOPS_CAS_H */
|
|
@ -18,6 +18,8 @@
|
||||||
#include <asm/bitops-op32.h>
|
#include <asm/bitops-op32.h>
|
||||||
#elif defined(CONFIG_CPU_SH4A)
|
#elif defined(CONFIG_CPU_SH4A)
|
||||||
#include <asm/bitops-llsc.h>
|
#include <asm/bitops-llsc.h>
|
||||||
|
#elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
|
||||||
|
#include <asm/bitops-cas.h>
|
||||||
#else
|
#else
|
||||||
#include <asm-generic/bitops/atomic.h>
|
#include <asm-generic/bitops/atomic.h>
|
||||||
#include <asm-generic/bitops/non-atomic.h>
|
#include <asm-generic/bitops/non-atomic.h>
|
||||||
|
|
24
arch/sh/include/asm/cmpxchg-cas.h
Normal file
24
arch/sh/include/asm/cmpxchg-cas.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef __ASM_SH_CMPXCHG_CAS_H
|
||||||
|
#define __ASM_SH_CMPXCHG_CAS_H
|
||||||
|
|
||||||
|
static inline unsigned long
|
||||||
|
__cmpxchg_u32(volatile u32 *m, unsigned long old, unsigned long new)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("cas.l %1,%0,@r0"
|
||||||
|
: "+r"(new)
|
||||||
|
: "r"(old), "z"(m)
|
||||||
|
: "t", "memory" );
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
|
||||||
|
{
|
||||||
|
unsigned long old;
|
||||||
|
do old = *m;
|
||||||
|
while (__cmpxchg_u32(m, old, val) != old);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <asm/cmpxchg-xchg.h>
|
||||||
|
|
||||||
|
#endif /* __ASM_SH_CMPXCHG_CAS_H */
|
|
@ -13,6 +13,8 @@
|
||||||
#include <asm/cmpxchg-grb.h>
|
#include <asm/cmpxchg-grb.h>
|
||||||
#elif defined(CONFIG_CPU_SH4A)
|
#elif defined(CONFIG_CPU_SH4A)
|
||||||
#include <asm/cmpxchg-llsc.h>
|
#include <asm/cmpxchg-llsc.h>
|
||||||
|
#elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
|
||||||
|
#include <asm/cmpxchg-cas.h>
|
||||||
#else
|
#else
|
||||||
#include <asm/cmpxchg-irq.h>
|
#include <asm/cmpxchg-irq.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
117
arch/sh/include/asm/spinlock-cas.h
Normal file
117
arch/sh/include/asm/spinlock-cas.h
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* include/asm-sh/spinlock-cas.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 SEI
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
* License. See the file "COPYING" in the main directory of this archive
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
#ifndef __ASM_SH_SPINLOCK_CAS_H
|
||||||
|
#define __ASM_SH_SPINLOCK_CAS_H
|
||||||
|
|
||||||
|
#include <asm/barrier.h>
|
||||||
|
#include <asm/processor.h>
|
||||||
|
|
||||||
|
static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("cas.l %1,%0,@r0"
|
||||||
|
: "+r"(new)
|
||||||
|
: "r"(old), "z"(p)
|
||||||
|
: "t", "memory" );
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Your basic SMP spinlocks, allowing only a single CPU anywhere
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define arch_spin_is_locked(x) ((x)->lock <= 0)
|
||||||
|
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||||
|
|
||||||
|
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
smp_cond_load_acquire(&lock->lock, VAL > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void arch_spin_lock(arch_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
while (!__sl_cas(&lock->lock, 1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void arch_spin_unlock(arch_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
__sl_cas(&lock->lock, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int arch_spin_trylock(arch_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
return __sl_cas(&lock->lock, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(x) ((x)->lock > 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write_can_lock - would write_trylock() succeed?
|
||||||
|
* @lock: the rwlock in question.
|
||||||
|
*/
|
||||||
|
#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
|
||||||
|
|
||||||
|
static inline void arch_read_lock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
unsigned old;
|
||||||
|
do old = rw->lock;
|
||||||
|
while (!old || __sl_cas(&rw->lock, old, old-1) != old);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void arch_read_unlock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
unsigned old;
|
||||||
|
do old = rw->lock;
|
||||||
|
while (__sl_cas(&rw->lock, old, old+1) != old);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void arch_write_lock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
while (__sl_cas(&rw->lock, RW_LOCK_BIAS, 0) != RW_LOCK_BIAS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void arch_write_unlock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
__sl_cas(&rw->lock, 0, RW_LOCK_BIAS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int arch_read_trylock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
unsigned old;
|
||||||
|
do old = rw->lock;
|
||||||
|
while (old && __sl_cas(&rw->lock, old, old-1) != old);
|
||||||
|
return !!old;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int arch_write_trylock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
return __sl_cas(&rw->lock, RW_LOCK_BIAS, 0) == RW_LOCK_BIAS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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_SH_SPINLOCK_CAS_H */
|
224
arch/sh/include/asm/spinlock-llsc.h
Normal file
224
arch/sh/include/asm/spinlock-llsc.h
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* include/asm-sh/spinlock-llsc.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002, 2003 Paul Mundt
|
||||||
|
* Copyright (C) 2006, 2007 Akio Idehara
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
* License. See the file "COPYING" in the main directory of this archive
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
#ifndef __ASM_SH_SPINLOCK_LLSC_H
|
||||||
|
#define __ASM_SH_SPINLOCK_LLSC_H
|
||||||
|
|
||||||
|
#include <asm/barrier.h>
|
||||||
|
#include <asm/processor.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Your basic SMP spinlocks, allowing only a single CPU anywhere
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define arch_spin_is_locked(x) ((x)->lock <= 0)
|
||||||
|
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||||
|
|
||||||
|
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
smp_cond_load_acquire(&lock->lock, VAL > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple spin lock operations. There are two variants, one clears IRQ's
|
||||||
|
* on the local processor, one does not.
|
||||||
|
*
|
||||||
|
* We make no fairness assumptions. They have a cost.
|
||||||
|
*/
|
||||||
|
static inline void arch_spin_lock(arch_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
unsigned long tmp;
|
||||||
|
unsigned long oldval;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"1: \n\t"
|
||||||
|
"movli.l @%2, %0 ! arch_spin_lock \n\t"
|
||||||
|
"mov %0, %1 \n\t"
|
||||||
|
"mov #0, %0 \n\t"
|
||||||
|
"movco.l %0, @%2 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
"cmp/pl %1 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
: "=&z" (tmp), "=&r" (oldval)
|
||||||
|
: "r" (&lock->lock)
|
||||||
|
: "t", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void arch_spin_unlock(arch_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
unsigned long tmp;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"mov #1, %0 ! arch_spin_unlock \n\t"
|
||||||
|
"mov.l %0, @%1 \n\t"
|
||||||
|
: "=&z" (tmp)
|
||||||
|
: "r" (&lock->lock)
|
||||||
|
: "t", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int arch_spin_trylock(arch_spinlock_t *lock)
|
||||||
|
{
|
||||||
|
unsigned long tmp, oldval;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"1: \n\t"
|
||||||
|
"movli.l @%2, %0 ! arch_spin_trylock \n\t"
|
||||||
|
"mov %0, %1 \n\t"
|
||||||
|
"mov #0, %0 \n\t"
|
||||||
|
"movco.l %0, @%2 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
"synco \n\t"
|
||||||
|
: "=&z" (tmp), "=&r" (oldval)
|
||||||
|
: "r" (&lock->lock)
|
||||||
|
: "t", "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
return oldval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(x) ((x)->lock > 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write_can_lock - would write_trylock() succeed?
|
||||||
|
* @lock: the rwlock in question.
|
||||||
|
*/
|
||||||
|
#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
|
||||||
|
|
||||||
|
static inline void arch_read_lock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
unsigned long tmp;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"1: \n\t"
|
||||||
|
"movli.l @%1, %0 ! arch_read_lock \n\t"
|
||||||
|
"cmp/pl %0 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
"add #-1, %0 \n\t"
|
||||||
|
"movco.l %0, @%1 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
: "=&z" (tmp)
|
||||||
|
: "r" (&rw->lock)
|
||||||
|
: "t", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void arch_read_unlock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
unsigned long tmp;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"1: \n\t"
|
||||||
|
"movli.l @%1, %0 ! arch_read_unlock \n\t"
|
||||||
|
"add #1, %0 \n\t"
|
||||||
|
"movco.l %0, @%1 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
: "=&z" (tmp)
|
||||||
|
: "r" (&rw->lock)
|
||||||
|
: "t", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void arch_write_lock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
unsigned long tmp;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"1: \n\t"
|
||||||
|
"movli.l @%1, %0 ! arch_write_lock \n\t"
|
||||||
|
"cmp/hs %2, %0 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
"sub %2, %0 \n\t"
|
||||||
|
"movco.l %0, @%1 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
: "=&z" (tmp)
|
||||||
|
: "r" (&rw->lock), "r" (RW_LOCK_BIAS)
|
||||||
|
: "t", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void arch_write_unlock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"mov.l %1, @%0 ! arch_write_unlock \n\t"
|
||||||
|
:
|
||||||
|
: "r" (&rw->lock), "r" (RW_LOCK_BIAS)
|
||||||
|
: "t", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int arch_read_trylock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
unsigned long tmp, oldval;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"1: \n\t"
|
||||||
|
"movli.l @%2, %0 ! arch_read_trylock \n\t"
|
||||||
|
"mov %0, %1 \n\t"
|
||||||
|
"cmp/pl %0 \n\t"
|
||||||
|
"bf 2f \n\t"
|
||||||
|
"add #-1, %0 \n\t"
|
||||||
|
"movco.l %0, @%2 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
"2: \n\t"
|
||||||
|
"synco \n\t"
|
||||||
|
: "=&z" (tmp), "=&r" (oldval)
|
||||||
|
: "r" (&rw->lock)
|
||||||
|
: "t", "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
return (oldval > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int arch_write_trylock(arch_rwlock_t *rw)
|
||||||
|
{
|
||||||
|
unsigned long tmp, oldval;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"1: \n\t"
|
||||||
|
"movli.l @%2, %0 ! arch_write_trylock \n\t"
|
||||||
|
"mov %0, %1 \n\t"
|
||||||
|
"cmp/hs %3, %0 \n\t"
|
||||||
|
"bf 2f \n\t"
|
||||||
|
"sub %3, %0 \n\t"
|
||||||
|
"2: \n\t"
|
||||||
|
"movco.l %0, @%2 \n\t"
|
||||||
|
"bf 1b \n\t"
|
||||||
|
"synco \n\t"
|
||||||
|
: "=&z" (tmp), "=&r" (oldval)
|
||||||
|
: "r" (&rw->lock), "r" (RW_LOCK_BIAS)
|
||||||
|
: "t", "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
return (oldval > (RW_LOCK_BIAS - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#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_SH_SPINLOCK_LLSC_H */
|
|
@ -11,222 +11,12 @@
|
||||||
#ifndef __ASM_SH_SPINLOCK_H
|
#ifndef __ASM_SH_SPINLOCK_H
|
||||||
#define __ASM_SH_SPINLOCK_H
|
#define __ASM_SH_SPINLOCK_H
|
||||||
|
|
||||||
/*
|
#if defined(CONFIG_CPU_SH4A)
|
||||||
* The only locking implemented here uses SH-4A opcodes. For others,
|
#include <asm/spinlock-llsc.h>
|
||||||
* split this out as per atomic-*.h.
|
#elif defined(CONFIG_CPU_J2)
|
||||||
*/
|
#include <asm/spinlock-cas.h>
|
||||||
#ifndef CONFIG_CPU_SH4A
|
#else
|
||||||
#error "Need movli.l/movco.l for spinlocks"
|
#error "The configured cpu type does not support spinlocks"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <asm/barrier.h>
|
|
||||||
#include <asm/processor.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Your basic SMP spinlocks, allowing only a single CPU anywhere
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define arch_spin_is_locked(x) ((x)->lock <= 0)
|
|
||||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
|
||||||
|
|
||||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
|
|
||||||
{
|
|
||||||
smp_cond_load_acquire(&lock->lock, VAL > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Simple spin lock operations. There are two variants, one clears IRQ's
|
|
||||||
* on the local processor, one does not.
|
|
||||||
*
|
|
||||||
* We make no fairness assumptions. They have a cost.
|
|
||||||
*/
|
|
||||||
static inline void arch_spin_lock(arch_spinlock_t *lock)
|
|
||||||
{
|
|
||||||
unsigned long tmp;
|
|
||||||
unsigned long oldval;
|
|
||||||
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"1: \n\t"
|
|
||||||
"movli.l @%2, %0 ! arch_spin_lock \n\t"
|
|
||||||
"mov %0, %1 \n\t"
|
|
||||||
"mov #0, %0 \n\t"
|
|
||||||
"movco.l %0, @%2 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
"cmp/pl %1 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
: "=&z" (tmp), "=&r" (oldval)
|
|
||||||
: "r" (&lock->lock)
|
|
||||||
: "t", "memory"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void arch_spin_unlock(arch_spinlock_t *lock)
|
|
||||||
{
|
|
||||||
unsigned long tmp;
|
|
||||||
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"mov #1, %0 ! arch_spin_unlock \n\t"
|
|
||||||
"mov.l %0, @%1 \n\t"
|
|
||||||
: "=&z" (tmp)
|
|
||||||
: "r" (&lock->lock)
|
|
||||||
: "t", "memory"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int arch_spin_trylock(arch_spinlock_t *lock)
|
|
||||||
{
|
|
||||||
unsigned long tmp, oldval;
|
|
||||||
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"1: \n\t"
|
|
||||||
"movli.l @%2, %0 ! arch_spin_trylock \n\t"
|
|
||||||
"mov %0, %1 \n\t"
|
|
||||||
"mov #0, %0 \n\t"
|
|
||||||
"movco.l %0, @%2 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
"synco \n\t"
|
|
||||||
: "=&z" (tmp), "=&r" (oldval)
|
|
||||||
: "r" (&lock->lock)
|
|
||||||
: "t", "memory"
|
|
||||||
);
|
|
||||||
|
|
||||||
return oldval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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(x) ((x)->lock > 0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* write_can_lock - would write_trylock() succeed?
|
|
||||||
* @lock: the rwlock in question.
|
|
||||||
*/
|
|
||||||
#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
|
|
||||||
|
|
||||||
static inline void arch_read_lock(arch_rwlock_t *rw)
|
|
||||||
{
|
|
||||||
unsigned long tmp;
|
|
||||||
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"1: \n\t"
|
|
||||||
"movli.l @%1, %0 ! arch_read_lock \n\t"
|
|
||||||
"cmp/pl %0 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
"add #-1, %0 \n\t"
|
|
||||||
"movco.l %0, @%1 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
: "=&z" (tmp)
|
|
||||||
: "r" (&rw->lock)
|
|
||||||
: "t", "memory"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void arch_read_unlock(arch_rwlock_t *rw)
|
|
||||||
{
|
|
||||||
unsigned long tmp;
|
|
||||||
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"1: \n\t"
|
|
||||||
"movli.l @%1, %0 ! arch_read_unlock \n\t"
|
|
||||||
"add #1, %0 \n\t"
|
|
||||||
"movco.l %0, @%1 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
: "=&z" (tmp)
|
|
||||||
: "r" (&rw->lock)
|
|
||||||
: "t", "memory"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void arch_write_lock(arch_rwlock_t *rw)
|
|
||||||
{
|
|
||||||
unsigned long tmp;
|
|
||||||
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"1: \n\t"
|
|
||||||
"movli.l @%1, %0 ! arch_write_lock \n\t"
|
|
||||||
"cmp/hs %2, %0 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
"sub %2, %0 \n\t"
|
|
||||||
"movco.l %0, @%1 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
: "=&z" (tmp)
|
|
||||||
: "r" (&rw->lock), "r" (RW_LOCK_BIAS)
|
|
||||||
: "t", "memory"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void arch_write_unlock(arch_rwlock_t *rw)
|
|
||||||
{
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"mov.l %1, @%0 ! arch_write_unlock \n\t"
|
|
||||||
:
|
|
||||||
: "r" (&rw->lock), "r" (RW_LOCK_BIAS)
|
|
||||||
: "t", "memory"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int arch_read_trylock(arch_rwlock_t *rw)
|
|
||||||
{
|
|
||||||
unsigned long tmp, oldval;
|
|
||||||
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"1: \n\t"
|
|
||||||
"movli.l @%2, %0 ! arch_read_trylock \n\t"
|
|
||||||
"mov %0, %1 \n\t"
|
|
||||||
"cmp/pl %0 \n\t"
|
|
||||||
"bf 2f \n\t"
|
|
||||||
"add #-1, %0 \n\t"
|
|
||||||
"movco.l %0, @%2 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
"2: \n\t"
|
|
||||||
"synco \n\t"
|
|
||||||
: "=&z" (tmp), "=&r" (oldval)
|
|
||||||
: "r" (&rw->lock)
|
|
||||||
: "t", "memory"
|
|
||||||
);
|
|
||||||
|
|
||||||
return (oldval > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int arch_write_trylock(arch_rwlock_t *rw)
|
|
||||||
{
|
|
||||||
unsigned long tmp, oldval;
|
|
||||||
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"1: \n\t"
|
|
||||||
"movli.l @%2, %0 ! arch_write_trylock \n\t"
|
|
||||||
"mov %0, %1 \n\t"
|
|
||||||
"cmp/hs %3, %0 \n\t"
|
|
||||||
"bf 2f \n\t"
|
|
||||||
"sub %3, %0 \n\t"
|
|
||||||
"2: \n\t"
|
|
||||||
"movco.l %0, @%2 \n\t"
|
|
||||||
"bf 1b \n\t"
|
|
||||||
"synco \n\t"
|
|
||||||
: "=&z" (tmp), "=&r" (oldval)
|
|
||||||
: "r" (&rw->lock), "r" (RW_LOCK_BIAS)
|
|
||||||
: "t", "memory"
|
|
||||||
);
|
|
||||||
|
|
||||||
return (oldval > (RW_LOCK_BIAS - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#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_SH_SPINLOCK_H */
|
#endif /* __ASM_SH_SPINLOCK_H */
|
||||||
|
|
Loading…
Reference in a new issue