1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/spinlock.h>
16#include <linux/module.h>
17#include <asm/processor.h>
18#include <arch/spr_def.h>
19
20#include "spinlock_common.h"
21
22void arch_spin_lock(arch_spinlock_t *lock)
23{
24 int my_ticket;
25 int iterations = 0;
26 int delta;
27
28 while ((my_ticket = __insn_tns((void *)&lock->next_ticket)) & 1)
29 delay_backoff(iterations++);
30
31
32 lock->next_ticket = my_ticket + TICKET_QUANTUM;
33
34
35 while ((delta = my_ticket - lock->current_ticket) != 0)
36 relax((128 / CYCLES_PER_RELAX_LOOP) * delta);
37}
38EXPORT_SYMBOL(arch_spin_lock);
39
40int arch_spin_trylock(arch_spinlock_t *lock)
41{
42
43
44
45
46
47 int my_ticket = __insn_tns((void *)&lock->next_ticket);
48
49 if (my_ticket == lock->current_ticket) {
50
51 lock->next_ticket = my_ticket + TICKET_QUANTUM;
52
53 return 1;
54 }
55
56 if (!(my_ticket & 1)) {
57
58 lock->next_ticket = my_ticket;
59 }
60
61 return 0;
62}
63EXPORT_SYMBOL(arch_spin_trylock);
64
65void arch_spin_unlock_wait(arch_spinlock_t *lock)
66{
67 u32 iterations = 0;
68 while (arch_spin_is_locked(lock))
69 delay_backoff(iterations++);
70}
71EXPORT_SYMBOL(arch_spin_unlock_wait);
72
73
74
75
76
77
78
79
80
81#define WR_NEXT_SHIFT _WR_NEXT_SHIFT
82#define WR_CURR_SHIFT _WR_CURR_SHIFT
83#define WR_WIDTH _WR_WIDTH
84#define WR_MASK ((1 << WR_WIDTH) - 1)
85
86
87
88
89
90#define RD_COUNT_SHIFT _RD_COUNT_SHIFT
91#define RD_COUNT_WIDTH _RD_COUNT_WIDTH
92#define RD_COUNT_MASK ((1 << RD_COUNT_WIDTH) - 1)
93
94
95
96
97
98
99
100
101
102
103
104inline int arch_read_trylock(arch_rwlock_t *rwlock)
105{
106 u32 val;
107 __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
108 val = __insn_tns((int *)&rwlock->lock);
109 if (likely((val << _RD_COUNT_WIDTH) == 0)) {
110 val += 1 << RD_COUNT_SHIFT;
111 rwlock->lock = val;
112 __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
113 BUG_ON(val == 0);
114 return 1;
115 }
116 if ((val & 1) == 0)
117 rwlock->lock = val;
118 __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
119 return 0;
120}
121EXPORT_SYMBOL(arch_read_trylock);
122
123
124
125
126
127
128
129
130
131void arch_read_lock(arch_rwlock_t *rwlock)
132{
133 u32 iterations = 0;
134 while (unlikely(!arch_read_trylock(rwlock)))
135 delay_backoff(iterations++);
136}
137EXPORT_SYMBOL(arch_read_lock);
138
139void arch_read_unlock(arch_rwlock_t *rwlock)
140{
141 u32 val, iterations = 0;
142
143 mb();
144 for (;;) {
145 __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
146 val = __insn_tns((int *)&rwlock->lock);
147 if (likely((val & 1) == 0)) {
148 rwlock->lock = val - (1 << _RD_COUNT_SHIFT);
149 __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
150 break;
151 }
152 __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
153 delay_backoff(iterations++);
154 }
155}
156EXPORT_SYMBOL(arch_read_unlock);
157
158
159
160
161
162
163void arch_write_lock(arch_rwlock_t *rwlock)
164{
165
166
167
168
169
170 u32 my_ticket_;
171 u32 iterations = 0;
172 u32 val = __insn_tns((int *)&rwlock->lock);
173
174 if (likely(val == 0)) {
175 rwlock->lock = 1 << _WR_NEXT_SHIFT;
176 return;
177 }
178
179
180
181
182
183 for (;;) {
184 if (!(val & 1)) {
185 if ((val >> RD_COUNT_SHIFT) == 0)
186 break;
187 rwlock->lock = val;
188 }
189 delay_backoff(iterations++);
190 val = __insn_tns((int *)&rwlock->lock);
191 }
192
193
194 rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT);
195 my_ticket_ = val >> WR_NEXT_SHIFT;
196
197
198 for (;;) {
199 u32 curr_ = val >> WR_CURR_SHIFT;
200 u32 delta = ((my_ticket_ - curr_) & WR_MASK);
201 if (likely(delta == 0))
202 break;
203
204
205 relax((256 / CYCLES_PER_RELAX_LOOP) * delta);
206
207
208
209
210
211
212 while ((val = rwlock->lock) & 1)
213 relax(4);
214 }
215}
216EXPORT_SYMBOL(arch_write_lock);
217
218int arch_write_trylock(arch_rwlock_t *rwlock)
219{
220 u32 val = __insn_tns((int *)&rwlock->lock);
221
222
223
224
225
226 if (unlikely(val != 0)) {
227 if (!(val & 1))
228 rwlock->lock = val;
229 return 0;
230 }
231
232
233 rwlock->lock = 1 << _WR_NEXT_SHIFT;
234 return 1;
235}
236EXPORT_SYMBOL(arch_write_trylock);
237
238void arch_write_unlock(arch_rwlock_t *rwlock)
239{
240 u32 val, eq, mask;
241
242 mb();
243 val = __insn_tns((int *)&rwlock->lock);
244 if (likely(val == (1 << _WR_NEXT_SHIFT))) {
245 rwlock->lock = 0;
246 return;
247 }
248 while (unlikely(val & 1)) {
249
250 relax(4);
251 val = __insn_tns((int *)&rwlock->lock);
252 }
253 mask = 1 << WR_CURR_SHIFT;
254 val = __insn_addb(val, mask);
255 eq = __insn_seqb(val, val << (WR_CURR_SHIFT - WR_NEXT_SHIFT));
256 val = __insn_mz(eq & mask, val);
257 rwlock->lock = val;
258}
259EXPORT_SYMBOL(arch_write_unlock);
260