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 1471872b5fSMax Filippov /* 1571872b5fSMax Filippov * spinlock 1671872b5fSMax Filippov * 1771872b5fSMax Filippov * There is at most one owner of a spinlock. There are not different 1871872b5fSMax Filippov * types of spinlock owners like there are for rwlocks (see below). 1971872b5fSMax Filippov * 2071872b5fSMax Filippov * When trying to obtain a spinlock, the function "spins" forever, or busy- 2171872b5fSMax Filippov * waits, until the lock is obtained. When spinning, presumably some other 2271872b5fSMax Filippov * owner will soon give up the spinlock making it available to others. Use 2371872b5fSMax Filippov * the trylock functions to avoid spinning forever. 2471872b5fSMax Filippov * 2571872b5fSMax Filippov * possible values: 2671872b5fSMax Filippov * 2771872b5fSMax Filippov * 0 nobody owns the spinlock 2871872b5fSMax Filippov * 1 somebody owns the spinlock 2971872b5fSMax Filippov */ 3071872b5fSMax Filippov 315515daa9SMax Filippov #define arch_spin_is_locked(x) ((x)->slock != 0) 325515daa9SMax Filippov #define arch_spin_unlock_wait(lock) \ 335515daa9SMax Filippov do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) 3471872b5fSMax Filippov 355515daa9SMax Filippov #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) 3671872b5fSMax Filippov 375515daa9SMax Filippov static inline void arch_spin_lock(arch_spinlock_t *lock) 3871872b5fSMax Filippov { 3971872b5fSMax Filippov unsigned long tmp; 4071872b5fSMax Filippov 4171872b5fSMax Filippov __asm__ __volatile__( 4271872b5fSMax Filippov " movi %0, 0\n" 4371872b5fSMax Filippov " wsr %0, scompare1\n" 4471872b5fSMax Filippov "1: movi %0, 1\n" 4571872b5fSMax Filippov " s32c1i %0, %1, 0\n" 4671872b5fSMax Filippov " bnez %0, 1b\n" 4771872b5fSMax Filippov : "=&a" (tmp) 4871872b5fSMax Filippov : "a" (&lock->slock) 4971872b5fSMax Filippov : "memory"); 5071872b5fSMax Filippov } 5171872b5fSMax Filippov 5271872b5fSMax Filippov /* Returns 1 if the lock is obtained, 0 otherwise. */ 5371872b5fSMax Filippov 545515daa9SMax Filippov static inline int arch_spin_trylock(arch_spinlock_t *lock) 5571872b5fSMax Filippov { 5671872b5fSMax Filippov unsigned long tmp; 5771872b5fSMax Filippov 5871872b5fSMax Filippov __asm__ __volatile__( 5971872b5fSMax Filippov " movi %0, 0\n" 6071872b5fSMax Filippov " wsr %0, scompare1\n" 6171872b5fSMax Filippov " movi %0, 1\n" 6271872b5fSMax Filippov " s32c1i %0, %1, 0\n" 6371872b5fSMax Filippov : "=&a" (tmp) 6471872b5fSMax Filippov : "a" (&lock->slock) 6571872b5fSMax Filippov : "memory"); 6671872b5fSMax Filippov 6771872b5fSMax Filippov return tmp == 0 ? 1 : 0; 6871872b5fSMax Filippov } 6971872b5fSMax Filippov 705515daa9SMax Filippov static inline void arch_spin_unlock(arch_spinlock_t *lock) 7171872b5fSMax Filippov { 7271872b5fSMax Filippov unsigned long tmp; 7371872b5fSMax Filippov 7471872b5fSMax Filippov __asm__ __volatile__( 7571872b5fSMax Filippov " movi %0, 0\n" 7671872b5fSMax Filippov " s32ri %0, %1, 0\n" 7771872b5fSMax Filippov : "=&a" (tmp) 7871872b5fSMax Filippov : "a" (&lock->slock) 7971872b5fSMax Filippov : "memory"); 8071872b5fSMax Filippov } 8171872b5fSMax Filippov 8271872b5fSMax Filippov /* 8371872b5fSMax Filippov * rwlock 8471872b5fSMax Filippov * 8571872b5fSMax Filippov * Read-write locks are really a more flexible spinlock. They allow 8671872b5fSMax Filippov * multiple readers but only one writer. Write ownership is exclusive 8771872b5fSMax Filippov * (i.e., all other readers and writers are blocked from ownership while 8871872b5fSMax Filippov * there is a write owner). These rwlocks are unfair to writers. Writers 8971872b5fSMax Filippov * can be starved for an indefinite time by readers. 9071872b5fSMax Filippov * 9171872b5fSMax Filippov * possible values: 9271872b5fSMax Filippov * 9371872b5fSMax Filippov * 0 nobody owns the rwlock 9471872b5fSMax Filippov * >0 one or more readers own the rwlock 9571872b5fSMax Filippov * (the positive value is the actual number of readers) 9671872b5fSMax Filippov * 0x80000000 one writer owns the rwlock, no other writers, no readers 9771872b5fSMax Filippov */ 9871872b5fSMax Filippov 995515daa9SMax Filippov #define arch_write_can_lock(x) ((x)->lock == 0) 10071872b5fSMax Filippov 1015515daa9SMax Filippov static inline void arch_write_lock(arch_rwlock_t *rw) 10271872b5fSMax Filippov { 10371872b5fSMax Filippov unsigned long tmp; 10471872b5fSMax Filippov 10571872b5fSMax Filippov __asm__ __volatile__( 10671872b5fSMax Filippov " movi %0, 0\n" 10771872b5fSMax Filippov " wsr %0, scompare1\n" 10871872b5fSMax Filippov "1: movi %0, 1\n" 10971872b5fSMax Filippov " slli %0, %0, 31\n" 11071872b5fSMax Filippov " s32c1i %0, %1, 0\n" 11171872b5fSMax Filippov " bnez %0, 1b\n" 11271872b5fSMax Filippov : "=&a" (tmp) 11371872b5fSMax Filippov : "a" (&rw->lock) 11471872b5fSMax Filippov : "memory"); 11571872b5fSMax Filippov } 11671872b5fSMax Filippov 11771872b5fSMax Filippov /* Returns 1 if the lock is obtained, 0 otherwise. */ 11871872b5fSMax Filippov 1195515daa9SMax Filippov static inline int arch_write_trylock(arch_rwlock_t *rw) 12071872b5fSMax Filippov { 12171872b5fSMax Filippov unsigned long tmp; 12271872b5fSMax Filippov 12371872b5fSMax Filippov __asm__ __volatile__( 12471872b5fSMax Filippov " movi %0, 0\n" 12571872b5fSMax Filippov " wsr %0, scompare1\n" 12671872b5fSMax Filippov " movi %0, 1\n" 12771872b5fSMax Filippov " slli %0, %0, 31\n" 12871872b5fSMax Filippov " s32c1i %0, %1, 0\n" 12971872b5fSMax Filippov : "=&a" (tmp) 13071872b5fSMax Filippov : "a" (&rw->lock) 13171872b5fSMax Filippov : "memory"); 13271872b5fSMax Filippov 13371872b5fSMax Filippov return tmp == 0 ? 1 : 0; 13471872b5fSMax Filippov } 13571872b5fSMax Filippov 1365515daa9SMax Filippov static inline void arch_write_unlock(arch_rwlock_t *rw) 13771872b5fSMax Filippov { 13871872b5fSMax Filippov unsigned long tmp; 13971872b5fSMax Filippov 14071872b5fSMax Filippov __asm__ __volatile__( 14171872b5fSMax Filippov " movi %0, 0\n" 14271872b5fSMax Filippov " s32ri %0, %1, 0\n" 14371872b5fSMax Filippov : "=&a" (tmp) 14471872b5fSMax Filippov : "a" (&rw->lock) 14571872b5fSMax Filippov : "memory"); 14671872b5fSMax Filippov } 14771872b5fSMax Filippov 1485515daa9SMax Filippov static inline void arch_read_lock(arch_rwlock_t *rw) 14971872b5fSMax Filippov { 15071872b5fSMax Filippov unsigned long tmp; 15171872b5fSMax Filippov unsigned long result; 15271872b5fSMax Filippov 15371872b5fSMax Filippov __asm__ __volatile__( 15471872b5fSMax Filippov "1: l32i %1, %2, 0\n" 15571872b5fSMax Filippov " bltz %1, 1b\n" 15671872b5fSMax Filippov " wsr %1, scompare1\n" 15771872b5fSMax Filippov " addi %0, %1, 1\n" 15871872b5fSMax Filippov " s32c1i %0, %2, 0\n" 15971872b5fSMax Filippov " bne %0, %1, 1b\n" 16071872b5fSMax Filippov : "=&a" (result), "=&a" (tmp) 16171872b5fSMax Filippov : "a" (&rw->lock) 16271872b5fSMax Filippov : "memory"); 16371872b5fSMax Filippov } 16471872b5fSMax Filippov 16571872b5fSMax Filippov /* Returns 1 if the lock is obtained, 0 otherwise. */ 16671872b5fSMax Filippov 1675515daa9SMax Filippov static inline int arch_read_trylock(arch_rwlock_t *rw) 16871872b5fSMax Filippov { 16971872b5fSMax Filippov unsigned long result; 17071872b5fSMax Filippov unsigned long tmp; 17171872b5fSMax Filippov 17271872b5fSMax Filippov __asm__ __volatile__( 17371872b5fSMax Filippov " l32i %1, %2, 0\n" 17471872b5fSMax Filippov " addi %0, %1, 1\n" 17571872b5fSMax Filippov " bltz %0, 1f\n" 17671872b5fSMax Filippov " wsr %1, scompare1\n" 17771872b5fSMax Filippov " s32c1i %0, %2, 0\n" 17871872b5fSMax Filippov " sub %0, %0, %1\n" 17971872b5fSMax Filippov "1:\n" 18071872b5fSMax Filippov : "=&a" (result), "=&a" (tmp) 18171872b5fSMax Filippov : "a" (&rw->lock) 18271872b5fSMax Filippov : "memory"); 18371872b5fSMax Filippov 18471872b5fSMax Filippov return result == 0; 18571872b5fSMax Filippov } 18671872b5fSMax Filippov 1875515daa9SMax Filippov static inline void arch_read_unlock(arch_rwlock_t *rw) 18871872b5fSMax Filippov { 18971872b5fSMax Filippov unsigned long tmp1, tmp2; 19071872b5fSMax Filippov 19171872b5fSMax Filippov __asm__ __volatile__( 19271872b5fSMax Filippov "1: l32i %1, %2, 0\n" 19371872b5fSMax Filippov " addi %0, %1, -1\n" 19471872b5fSMax Filippov " wsr %1, scompare1\n" 19571872b5fSMax Filippov " s32c1i %0, %2, 0\n" 19671872b5fSMax Filippov " bne %0, %1, 1b\n" 19771872b5fSMax Filippov : "=&a" (tmp1), "=&a" (tmp2) 19871872b5fSMax Filippov : "a" (&rw->lock) 19971872b5fSMax Filippov : "memory"); 20071872b5fSMax Filippov } 201367b8112SChris Zankel 2025515daa9SMax Filippov #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) 2035515daa9SMax Filippov #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) 2045515daa9SMax Filippov 205367b8112SChris Zankel #endif /* _XTENSA_SPINLOCK_H */ 206