1 /*
2 * include/asm-xtensa/spinlock.h
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (C) 2001 - 2005 Tensilica Inc.
9 */
10
11 #ifndef _XTENSA_SPINLOCK_H
12 #define _XTENSA_SPINLOCK_H
13
14 #include <asm/barrier.h>
15 #include <asm/processor.h>
16
17 /*
18 * spinlock
19 *
20 * There is at most one owner of a spinlock. There are not different
21 * types of spinlock owners like there are for rwlocks (see below).
22 *
23 * When trying to obtain a spinlock, the function "spins" forever, or busy-
24 * waits, until the lock is obtained. When spinning, presumably some other
25 * owner will soon give up the spinlock making it available to others. Use
26 * the trylock functions to avoid spinning forever.
27 *
28 * possible values:
29 *
30 * 0 nobody owns the spinlock
31 * 1 somebody owns the spinlock
32 */
33
34 #define arch_spin_is_locked(x) ((x)->slock != 0)
35
arch_spin_lock(arch_spinlock_t * lock)36 static inline void arch_spin_lock(arch_spinlock_t *lock)
37 {
38 unsigned long tmp;
39
40 __asm__ __volatile__(
41 " movi %0, 0\n"
42 " wsr %0, scompare1\n"
43 "1: movi %0, 1\n"
44 " s32c1i %0, %1, 0\n"
45 " bnez %0, 1b\n"
46 : "=&a" (tmp)
47 : "a" (&lock->slock)
48 : "memory");
49 }
50
51 /* Returns 1 if the lock is obtained, 0 otherwise. */
52
arch_spin_trylock(arch_spinlock_t * lock)53 static inline int arch_spin_trylock(arch_spinlock_t *lock)
54 {
55 unsigned long tmp;
56
57 __asm__ __volatile__(
58 " movi %0, 0\n"
59 " wsr %0, scompare1\n"
60 " movi %0, 1\n"
61 " s32c1i %0, %1, 0\n"
62 : "=&a" (tmp)
63 : "a" (&lock->slock)
64 : "memory");
65
66 return tmp == 0 ? 1 : 0;
67 }
68
arch_spin_unlock(arch_spinlock_t * lock)69 static inline void arch_spin_unlock(arch_spinlock_t *lock)
70 {
71 unsigned long tmp;
72
73 __asm__ __volatile__(
74 " movi %0, 0\n"
75 " s32ri %0, %1, 0\n"
76 : "=&a" (tmp)
77 : "a" (&lock->slock)
78 : "memory");
79 }
80
81 /*
82 * rwlock
83 *
84 * Read-write locks are really a more flexible spinlock. They allow
85 * multiple readers but only one writer. Write ownership is exclusive
86 * (i.e., all other readers and writers are blocked from ownership while
87 * there is a write owner). These rwlocks are unfair to writers. Writers
88 * can be starved for an indefinite time by readers.
89 *
90 * possible values:
91 *
92 * 0 nobody owns the rwlock
93 * >0 one or more readers own the rwlock
94 * (the positive value is the actual number of readers)
95 * 0x80000000 one writer owns the rwlock, no other writers, no readers
96 */
97
arch_write_lock(arch_rwlock_t * rw)98 static inline void arch_write_lock(arch_rwlock_t *rw)
99 {
100 unsigned long tmp;
101
102 __asm__ __volatile__(
103 " movi %0, 0\n"
104 " wsr %0, scompare1\n"
105 "1: movi %0, 1\n"
106 " slli %0, %0, 31\n"
107 " s32c1i %0, %1, 0\n"
108 " bnez %0, 1b\n"
109 : "=&a" (tmp)
110 : "a" (&rw->lock)
111 : "memory");
112 }
113
114 /* Returns 1 if the lock is obtained, 0 otherwise. */
115
arch_write_trylock(arch_rwlock_t * rw)116 static inline int arch_write_trylock(arch_rwlock_t *rw)
117 {
118 unsigned long tmp;
119
120 __asm__ __volatile__(
121 " movi %0, 0\n"
122 " wsr %0, scompare1\n"
123 " movi %0, 1\n"
124 " slli %0, %0, 31\n"
125 " s32c1i %0, %1, 0\n"
126 : "=&a" (tmp)
127 : "a" (&rw->lock)
128 : "memory");
129
130 return tmp == 0 ? 1 : 0;
131 }
132
arch_write_unlock(arch_rwlock_t * rw)133 static inline void arch_write_unlock(arch_rwlock_t *rw)
134 {
135 unsigned long tmp;
136
137 __asm__ __volatile__(
138 " movi %0, 0\n"
139 " s32ri %0, %1, 0\n"
140 : "=&a" (tmp)
141 : "a" (&rw->lock)
142 : "memory");
143 }
144
arch_read_lock(arch_rwlock_t * rw)145 static inline void arch_read_lock(arch_rwlock_t *rw)
146 {
147 unsigned long tmp;
148 unsigned long result;
149
150 __asm__ __volatile__(
151 "1: l32i %1, %2, 0\n"
152 " bltz %1, 1b\n"
153 " wsr %1, scompare1\n"
154 " addi %0, %1, 1\n"
155 " s32c1i %0, %2, 0\n"
156 " bne %0, %1, 1b\n"
157 : "=&a" (result), "=&a" (tmp)
158 : "a" (&rw->lock)
159 : "memory");
160 }
161
162 /* Returns 1 if the lock is obtained, 0 otherwise. */
163
arch_read_trylock(arch_rwlock_t * rw)164 static inline int arch_read_trylock(arch_rwlock_t *rw)
165 {
166 unsigned long result;
167 unsigned long tmp;
168
169 __asm__ __volatile__(
170 " l32i %1, %2, 0\n"
171 " addi %0, %1, 1\n"
172 " bltz %0, 1f\n"
173 " wsr %1, scompare1\n"
174 " s32c1i %0, %2, 0\n"
175 " sub %0, %0, %1\n"
176 "1:\n"
177 : "=&a" (result), "=&a" (tmp)
178 : "a" (&rw->lock)
179 : "memory");
180
181 return result == 0;
182 }
183
arch_read_unlock(arch_rwlock_t * rw)184 static inline void arch_read_unlock(arch_rwlock_t *rw)
185 {
186 unsigned long tmp1, tmp2;
187
188 __asm__ __volatile__(
189 "1: l32i %1, %2, 0\n"
190 " addi %0, %1, -1\n"
191 " wsr %1, scompare1\n"
192 " s32c1i %0, %2, 0\n"
193 " bne %0, %1, 1b\n"
194 : "=&a" (tmp1), "=&a" (tmp2)
195 : "a" (&rw->lock)
196 : "memory");
197 }
198
199 #endif /* _XTENSA_SPINLOCK_H */
200