]>
Commit | Line | Data |
---|---|---|
58f07778 DD |
1 | /***********************license start*************** |
2 | * Author: Cavium Networks | |
3 | * | |
4 | * Contact: support@caviumnetworks.com | |
5 | * This file is part of the OCTEON SDK | |
6 | * | |
7 | * Copyright (c) 2003-2008 Cavium Networks | |
8 | * | |
9 | * This file is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License, Version 2, as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This file is distributed in the hope that it will be useful, but | |
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | |
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | |
16 | * NONINFRINGEMENT. See the GNU General Public License for more | |
17 | * details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this file; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * or visit http://www.gnu.org/licenses/. | |
23 | * | |
24 | * This file may also be available under a different license from Cavium. | |
25 | * Contact Cavium Networks for more information | |
26 | ***********************license end**************************************/ | |
27 | ||
28 | /** | |
70342287 | 29 | * Implementation of spinlocks for Octeon CVMX. Although similar in |
58f07778 DD |
30 | * function to Linux kernel spinlocks, they are not compatible. |
31 | * Octeon CVMX spinlocks are only used to synchronize with the boot | |
32 | * monitor and other non-Linux programs running in the system. | |
33 | */ | |
34 | ||
35 | #ifndef __CVMX_SPINLOCK_H__ | |
36 | #define __CVMX_SPINLOCK_H__ | |
37 | ||
a1ce3928 | 38 | #include <asm/octeon/cvmx-asm.h> |
58f07778 DD |
39 | |
40 | /* Spinlocks for Octeon */ | |
41 | ||
42 | /* define these to enable recursive spinlock debugging */ | |
43 | /*#define CVMX_SPINLOCK_DEBUG */ | |
44 | ||
45 | /** | |
46 | * Spinlocks for Octeon CVMX | |
47 | */ | |
48 | typedef struct { | |
49 | volatile uint32_t value; | |
50 | } cvmx_spinlock_t; | |
51 | ||
52 | /* note - macros not expanded in inline ASM, so values hardcoded */ | |
70342287 RB |
53 | #define CVMX_SPINLOCK_UNLOCKED_VAL 0 |
54 | #define CVMX_SPINLOCK_LOCKED_VAL 1 | |
58f07778 DD |
55 | |
56 | #define CVMX_SPINLOCK_UNLOCKED_INITIALIZER {CVMX_SPINLOCK_UNLOCKED_VAL} | |
57 | ||
58 | /** | |
59 | * Initialize a spinlock | |
60 | * | |
61 | * @lock: Lock to initialize | |
62 | */ | |
63 | static inline void cvmx_spinlock_init(cvmx_spinlock_t *lock) | |
64 | { | |
65 | lock->value = CVMX_SPINLOCK_UNLOCKED_VAL; | |
66 | } | |
67 | ||
68 | /** | |
69 | * Return non-zero if the spinlock is currently locked | |
70 | * | |
71 | * @lock: Lock to check | |
72 | * Returns Non-zero if locked | |
73 | */ | |
74 | static inline int cvmx_spinlock_locked(cvmx_spinlock_t *lock) | |
75 | { | |
76 | return lock->value != CVMX_SPINLOCK_UNLOCKED_VAL; | |
77 | } | |
78 | ||
79 | /** | |
80 | * Releases lock | |
81 | * | |
82 | * @lock: pointer to lock structure | |
83 | */ | |
84 | static inline void cvmx_spinlock_unlock(cvmx_spinlock_t *lock) | |
85 | { | |
86 | CVMX_SYNCWS; | |
87 | lock->value = 0; | |
88 | CVMX_SYNCWS; | |
89 | } | |
90 | ||
91 | /** | |
92 | * Attempts to take the lock, but does not spin if lock is not available. | |
93 | * May take some time to acquire the lock even if it is available | |
94 | * due to the ll/sc not succeeding. | |
95 | * | |
96 | * @lock: pointer to lock structure | |
97 | * | |
98 | * Returns 0: lock successfully taken | |
70342287 | 99 | * 1: lock not taken, held by someone else |
58f07778 DD |
100 | * These return values match the Linux semantics. |
101 | */ | |
102 | ||
103 | static inline unsigned int cvmx_spinlock_trylock(cvmx_spinlock_t *lock) | |
104 | { | |
105 | unsigned int tmp; | |
106 | ||
70342287 | 107 | __asm__ __volatile__(".set noreorder \n" |
58f07778 DD |
108 | "1: ll %[tmp], %[val] \n" |
109 | /* if lock held, fail immediately */ | |
70342287 RB |
110 | " bnez %[tmp], 2f \n" |
111 | " li %[tmp], 1 \n" | |
112 | " sc %[tmp], %[val] \n" | |
113 | " beqz %[tmp], 1b \n" | |
114 | " li %[tmp], 0 \n" | |
115 | "2: \n" | |
116 | ".set reorder \n" : | |
58f07778 DD |
117 | [val] "+m"(lock->value), [tmp] "=&r"(tmp) |
118 | : : "memory"); | |
119 | ||
120 | return tmp != 0; /* normalize to 0 or 1 */ | |
121 | } | |
122 | ||
123 | /** | |
124 | * Gets lock, spins until lock is taken | |
125 | * | |
126 | * @lock: pointer to lock structure | |
127 | */ | |
128 | static inline void cvmx_spinlock_lock(cvmx_spinlock_t *lock) | |
129 | { | |
130 | unsigned int tmp; | |
131 | ||
70342287 | 132 | __asm__ __volatile__(".set noreorder \n" |
58f07778 | 133 | "1: ll %[tmp], %[val] \n" |
70342287 RB |
134 | " bnez %[tmp], 1b \n" |
135 | " li %[tmp], 1 \n" | |
136 | " sc %[tmp], %[val] \n" | |
137 | " beqz %[tmp], 1b \n" | |
138 | " nop \n" | |
139 | ".set reorder \n" : | |
58f07778 DD |
140 | [val] "+m"(lock->value), [tmp] "=&r"(tmp) |
141 | : : "memory"); | |
142 | ||
143 | } | |
144 | ||
145 | /** ******************************************************************** | |
146 | * Bit spinlocks | |
147 | * These spinlocks use a single bit (bit 31) of a 32 bit word for locking. | |
148 | * The rest of the bits in the word are left undisturbed. This enables more | |
149 | * compact data structures as only 1 bit is consumed for the lock. | |
150 | * | |
151 | */ | |
152 | ||
153 | /** | |
154 | * Gets lock, spins until lock is taken | |
155 | * Preserves the low 31 bits of the 32 bit | |
156 | * word used for the lock. | |
157 | * | |
158 | * | |
159 | * @word: word to lock bit 31 of | |
160 | */ | |
161 | static inline void cvmx_spinlock_bit_lock(uint32_t *word) | |
162 | { | |
163 | unsigned int tmp; | |
164 | unsigned int sav; | |
165 | ||
70342287 RB |
166 | __asm__ __volatile__(".set noreorder \n" |
167 | ".set noat \n" | |
58f07778 | 168 | "1: ll %[tmp], %[val] \n" |
70342287 RB |
169 | " bbit1 %[tmp], 31, 1b \n" |
170 | " li $at, 1 \n" | |
171 | " ins %[tmp], $at, 31, 1 \n" | |
172 | " sc %[tmp], %[val] \n" | |
173 | " beqz %[tmp], 1b \n" | |
174 | " nop \n" | |
175 | ".set at \n" | |
176 | ".set reorder \n" : | |
58f07778 DD |
177 | [val] "+m"(*word), [tmp] "=&r"(tmp), [sav] "=&r"(sav) |
178 | : : "memory"); | |
179 | ||
180 | } | |
181 | ||
182 | /** | |
183 | * Attempts to get lock, returns immediately with success/failure | |
184 | * Preserves the low 31 bits of the 32 bit | |
185 | * word used for the lock. | |
186 | * | |
187 | * | |
188 | * @word: word to lock bit 31 of | |
189 | * Returns 0: lock successfully taken | |
70342287 | 190 | * 1: lock not taken, held by someone else |
58f07778 DD |
191 | * These return values match the Linux semantics. |
192 | */ | |
193 | static inline unsigned int cvmx_spinlock_bit_trylock(uint32_t *word) | |
194 | { | |
195 | unsigned int tmp; | |
196 | ||
197 | __asm__ __volatile__(".set noreorder\n\t" | |
198 | ".set noat\n" | |
199 | "1: ll %[tmp], %[val] \n" | |
200 | /* if lock held, fail immediately */ | |
70342287 RB |
201 | " bbit1 %[tmp], 31, 2f \n" |
202 | " li $at, 1 \n" | |
203 | " ins %[tmp], $at, 31, 1 \n" | |
204 | " sc %[tmp], %[val] \n" | |
205 | " beqz %[tmp], 1b \n" | |
206 | " li %[tmp], 0 \n" | |
207 | "2: \n" | |
208 | ".set at \n" | |
209 | ".set reorder \n" : | |
58f07778 DD |
210 | [val] "+m"(*word), [tmp] "=&r"(tmp) |
211 | : : "memory"); | |
212 | ||
213 | return tmp != 0; /* normalize to 0 or 1 */ | |
214 | } | |
215 | ||
216 | /** | |
217 | * Releases bit lock | |
218 | * | |
219 | * Unconditionally clears bit 31 of the lock word. Note that this is | |
220 | * done non-atomically, as this implementation assumes that the rest | |
221 | * of the bits in the word are protected by the lock. | |
222 | * | |
223 | * @word: word to unlock bit 31 in | |
224 | */ | |
225 | static inline void cvmx_spinlock_bit_unlock(uint32_t *word) | |
226 | { | |
227 | CVMX_SYNCWS; | |
228 | *word &= ~(1UL << 31); | |
229 | CVMX_SYNCWS; | |
230 | } | |
231 | ||
232 | #endif /* __CVMX_SPINLOCK_H__ */ |