xref: /openbmc/linux/arch/xtensa/include/asm/spinlock.h (revision 726328d9)
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