1367b8112SChris Zankel /* 2367b8112SChris Zankel * include/asm-xtensa/spinlock.h 3367b8112SChris Zankel * 4367b8112SChris Zankel * This file is subject to the terms and conditions of the GNU General Public 5367b8112SChris Zankel * License. See the file "COPYING" in the main directory of this archive 6367b8112SChris Zankel * for more details. 7367b8112SChris Zankel * 8367b8112SChris Zankel * Copyright (C) 2001 - 2005 Tensilica Inc. 9367b8112SChris Zankel */ 10367b8112SChris Zankel 11367b8112SChris Zankel #ifndef _XTENSA_SPINLOCK_H 12367b8112SChris Zankel #define _XTENSA_SPINLOCK_H 13367b8112SChris Zankel 14726328d9SPeter Zijlstra #include <asm/barrier.h> 15726328d9SPeter Zijlstra #include <asm/processor.h> 16726328d9SPeter Zijlstra 1771872b5fSMax Filippov /* 1871872b5fSMax Filippov * spinlock 1971872b5fSMax Filippov * 2071872b5fSMax Filippov * There is at most one owner of a spinlock. There are not different 2171872b5fSMax Filippov * types of spinlock owners like there are for rwlocks (see below). 2271872b5fSMax Filippov * 2371872b5fSMax Filippov * When trying to obtain a spinlock, the function "spins" forever, or busy- 2471872b5fSMax Filippov * waits, until the lock is obtained. When spinning, presumably some other 2571872b5fSMax Filippov * owner will soon give up the spinlock making it available to others. Use 2671872b5fSMax Filippov * the trylock functions to avoid spinning forever. 2771872b5fSMax Filippov * 2871872b5fSMax Filippov * possible values: 2971872b5fSMax Filippov * 3071872b5fSMax Filippov * 0 nobody owns the spinlock 3171872b5fSMax Filippov * 1 somebody owns the spinlock 3271872b5fSMax Filippov */ 3371872b5fSMax Filippov 345515daa9SMax Filippov #define arch_spin_is_locked(x) ((x)->slock != 0) 35726328d9SPeter Zijlstra 36726328d9SPeter Zijlstra static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) 37726328d9SPeter Zijlstra { 38726328d9SPeter Zijlstra smp_cond_load_acquire(&lock->slock, !VAL); 39726328d9SPeter Zijlstra } 4071872b5fSMax Filippov 415515daa9SMax Filippov #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) 4271872b5fSMax Filippov 435515daa9SMax Filippov static inline void arch_spin_lock(arch_spinlock_t *lock) 4471872b5fSMax Filippov { 4571872b5fSMax Filippov unsigned long tmp; 4671872b5fSMax Filippov 4771872b5fSMax Filippov __asm__ __volatile__( 4871872b5fSMax Filippov " movi %0, 0\n" 4971872b5fSMax Filippov " wsr %0, scompare1\n" 5071872b5fSMax Filippov "1: movi %0, 1\n" 5171872b5fSMax Filippov " s32c1i %0, %1, 0\n" 5271872b5fSMax Filippov " bnez %0, 1b\n" 5371872b5fSMax Filippov : "=&a" (tmp) 5471872b5fSMax Filippov : "a" (&lock->slock) 5571872b5fSMax Filippov : "memory"); 5671872b5fSMax Filippov } 5771872b5fSMax Filippov 5871872b5fSMax Filippov /* Returns 1 if the lock is obtained, 0 otherwise. */ 5971872b5fSMax Filippov 605515daa9SMax Filippov static inline int arch_spin_trylock(arch_spinlock_t *lock) 6171872b5fSMax Filippov { 6271872b5fSMax Filippov unsigned long tmp; 6371872b5fSMax Filippov 6471872b5fSMax Filippov __asm__ __volatile__( 6571872b5fSMax Filippov " movi %0, 0\n" 6671872b5fSMax Filippov " wsr %0, scompare1\n" 6771872b5fSMax Filippov " movi %0, 1\n" 6871872b5fSMax Filippov " s32c1i %0, %1, 0\n" 6971872b5fSMax Filippov : "=&a" (tmp) 7071872b5fSMax Filippov : "a" (&lock->slock) 7171872b5fSMax Filippov : "memory"); 7271872b5fSMax Filippov 7371872b5fSMax Filippov return tmp == 0 ? 1 : 0; 7471872b5fSMax Filippov } 7571872b5fSMax Filippov 765515daa9SMax Filippov static inline void arch_spin_unlock(arch_spinlock_t *lock) 7771872b5fSMax Filippov { 7871872b5fSMax Filippov unsigned long tmp; 7971872b5fSMax Filippov 8071872b5fSMax Filippov __asm__ __volatile__( 8171872b5fSMax Filippov " movi %0, 0\n" 8271872b5fSMax Filippov " s32ri %0, %1, 0\n" 8371872b5fSMax Filippov : "=&a" (tmp) 8471872b5fSMax Filippov : "a" (&lock->slock) 8571872b5fSMax Filippov : "memory"); 8671872b5fSMax Filippov } 8771872b5fSMax Filippov 8871872b5fSMax Filippov /* 8971872b5fSMax Filippov * rwlock 9071872b5fSMax Filippov * 9171872b5fSMax Filippov * Read-write locks are really a more flexible spinlock. They allow 9271872b5fSMax Filippov * multiple readers but only one writer. Write ownership is exclusive 9371872b5fSMax Filippov * (i.e., all other readers and writers are blocked from ownership while 9471872b5fSMax Filippov * there is a write owner). These rwlocks are unfair to writers. Writers 9571872b5fSMax Filippov * can be starved for an indefinite time by readers. 9671872b5fSMax Filippov * 9771872b5fSMax Filippov * possible values: 9871872b5fSMax Filippov * 9971872b5fSMax Filippov * 0 nobody owns the rwlock 10071872b5fSMax Filippov * >0 one or more readers own the rwlock 10171872b5fSMax Filippov * (the positive value is the actual number of readers) 10271872b5fSMax Filippov * 0x80000000 one writer owns the rwlock, no other writers, no readers 10371872b5fSMax Filippov */ 10471872b5fSMax Filippov 1055515daa9SMax Filippov #define arch_write_can_lock(x) ((x)->lock == 0) 10671872b5fSMax Filippov 1075515daa9SMax Filippov static inline void arch_write_lock(arch_rwlock_t *rw) 10871872b5fSMax Filippov { 10971872b5fSMax Filippov unsigned long tmp; 11071872b5fSMax Filippov 11171872b5fSMax Filippov __asm__ __volatile__( 11271872b5fSMax Filippov " movi %0, 0\n" 11371872b5fSMax Filippov " wsr %0, scompare1\n" 11471872b5fSMax Filippov "1: movi %0, 1\n" 11571872b5fSMax Filippov " slli %0, %0, 31\n" 11671872b5fSMax Filippov " s32c1i %0, %1, 0\n" 11771872b5fSMax Filippov " bnez %0, 1b\n" 11871872b5fSMax Filippov : "=&a" (tmp) 11971872b5fSMax Filippov : "a" (&rw->lock) 12071872b5fSMax Filippov : "memory"); 12171872b5fSMax Filippov } 12271872b5fSMax Filippov 12371872b5fSMax Filippov /* Returns 1 if the lock is obtained, 0 otherwise. */ 12471872b5fSMax Filippov 1255515daa9SMax Filippov static inline int arch_write_trylock(arch_rwlock_t *rw) 12671872b5fSMax Filippov { 12771872b5fSMax Filippov unsigned long tmp; 12871872b5fSMax Filippov 12971872b5fSMax Filippov __asm__ __volatile__( 13071872b5fSMax Filippov " movi %0, 0\n" 13171872b5fSMax Filippov " wsr %0, scompare1\n" 13271872b5fSMax Filippov " movi %0, 1\n" 13371872b5fSMax Filippov " slli %0, %0, 31\n" 13471872b5fSMax Filippov " s32c1i %0, %1, 0\n" 13571872b5fSMax Filippov : "=&a" (tmp) 13671872b5fSMax Filippov : "a" (&rw->lock) 13771872b5fSMax Filippov : "memory"); 13871872b5fSMax Filippov 13971872b5fSMax Filippov return tmp == 0 ? 1 : 0; 14071872b5fSMax Filippov } 14171872b5fSMax Filippov 1425515daa9SMax Filippov static inline void arch_write_unlock(arch_rwlock_t *rw) 14371872b5fSMax Filippov { 14471872b5fSMax Filippov unsigned long tmp; 14571872b5fSMax Filippov 14671872b5fSMax Filippov __asm__ __volatile__( 14771872b5fSMax Filippov " movi %0, 0\n" 14871872b5fSMax Filippov " s32ri %0, %1, 0\n" 14971872b5fSMax Filippov : "=&a" (tmp) 15071872b5fSMax Filippov : "a" (&rw->lock) 15171872b5fSMax Filippov : "memory"); 15271872b5fSMax Filippov } 15371872b5fSMax Filippov 1545515daa9SMax Filippov static inline void arch_read_lock(arch_rwlock_t *rw) 15571872b5fSMax Filippov { 15671872b5fSMax Filippov unsigned long tmp; 15771872b5fSMax Filippov unsigned long result; 15871872b5fSMax Filippov 15971872b5fSMax Filippov __asm__ __volatile__( 16071872b5fSMax Filippov "1: l32i %1, %2, 0\n" 16171872b5fSMax Filippov " bltz %1, 1b\n" 16271872b5fSMax Filippov " wsr %1, scompare1\n" 16371872b5fSMax Filippov " addi %0, %1, 1\n" 16471872b5fSMax Filippov " s32c1i %0, %2, 0\n" 16571872b5fSMax Filippov " bne %0, %1, 1b\n" 16671872b5fSMax Filippov : "=&a" (result), "=&a" (tmp) 16771872b5fSMax Filippov : "a" (&rw->lock) 16871872b5fSMax Filippov : "memory"); 16971872b5fSMax Filippov } 17071872b5fSMax Filippov 17171872b5fSMax Filippov /* Returns 1 if the lock is obtained, 0 otherwise. */ 17271872b5fSMax Filippov 1735515daa9SMax Filippov static inline int arch_read_trylock(arch_rwlock_t *rw) 17471872b5fSMax Filippov { 17571872b5fSMax Filippov unsigned long result; 17671872b5fSMax Filippov unsigned long tmp; 17771872b5fSMax Filippov 17871872b5fSMax Filippov __asm__ __volatile__( 17971872b5fSMax Filippov " l32i %1, %2, 0\n" 18071872b5fSMax Filippov " addi %0, %1, 1\n" 18171872b5fSMax Filippov " bltz %0, 1f\n" 18271872b5fSMax Filippov " wsr %1, scompare1\n" 18371872b5fSMax Filippov " s32c1i %0, %2, 0\n" 18471872b5fSMax Filippov " sub %0, %0, %1\n" 18571872b5fSMax Filippov "1:\n" 18671872b5fSMax Filippov : "=&a" (result), "=&a" (tmp) 18771872b5fSMax Filippov : "a" (&rw->lock) 18871872b5fSMax Filippov : "memory"); 18971872b5fSMax Filippov 19071872b5fSMax Filippov return result == 0; 19171872b5fSMax Filippov } 19271872b5fSMax Filippov 1935515daa9SMax Filippov static inline void arch_read_unlock(arch_rwlock_t *rw) 19471872b5fSMax Filippov { 19571872b5fSMax Filippov unsigned long tmp1, tmp2; 19671872b5fSMax Filippov 19771872b5fSMax Filippov __asm__ __volatile__( 19871872b5fSMax Filippov "1: l32i %1, %2, 0\n" 19971872b5fSMax Filippov " addi %0, %1, -1\n" 20071872b5fSMax Filippov " wsr %1, scompare1\n" 20171872b5fSMax Filippov " s32c1i %0, %2, 0\n" 20271872b5fSMax Filippov " bne %0, %1, 1b\n" 20371872b5fSMax Filippov : "=&a" (tmp1), "=&a" (tmp2) 20471872b5fSMax Filippov : "a" (&rw->lock) 20571872b5fSMax Filippov : "memory"); 20671872b5fSMax Filippov } 207367b8112SChris Zankel 2085515daa9SMax Filippov #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) 2095515daa9SMax Filippov #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) 2105515daa9SMax Filippov 211367b8112SChris Zankel #endif /* _XTENSA_SPINLOCK_H */ 212