diff options
author | Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> | 2008-02-07 03:16:19 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 11:42:32 -0500 |
commit | 7fa2ac3728ce828070fa3d5846c08157fe5ef431 (patch) | |
tree | 46d8af0c873bac8d03fd7c166420c9ee5fca7fca | |
parent | df0f65f02a55888feae52a7e7d59d29f5edd400d (diff) |
local_t m32r use architecture specific cmpxchg_local
On m32r, use the new cmpxchg_local as primitive for the local_cmpxchg
operation.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Acked-by: Hirokazu Takata <takata@linux-m32r.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/asm-m32r/local.h | 362 |
1 files changed, 361 insertions, 1 deletions
diff --git a/include/asm-m32r/local.h b/include/asm-m32r/local.h index def29d095740..22256d138630 100644 --- a/include/asm-m32r/local.h +++ b/include/asm-m32r/local.h | |||
@@ -1,6 +1,366 @@ | |||
1 | #ifndef __M32R_LOCAL_H | 1 | #ifndef __M32R_LOCAL_H |
2 | #define __M32R_LOCAL_H | 2 | #define __M32R_LOCAL_H |
3 | 3 | ||
4 | #include <asm-generic/local.h> | 4 | /* |
5 | * linux/include/asm-m32r/local.h | ||
6 | * | ||
7 | * M32R version: | ||
8 | * Copyright (C) 2001, 2002 Hitoshi Yamamoto | ||
9 | * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org> | ||
10 | * Copyright (C) 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> | ||
11 | */ | ||
12 | |||
13 | #include <linux/percpu.h> | ||
14 | #include <asm/assembler.h> | ||
15 | #include <asm/system.h> | ||
16 | #include <asm/local.h> | ||
17 | |||
18 | /* | ||
19 | * Atomic operations that C can't guarantee us. Useful for | ||
20 | * resource counting etc.. | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * Make sure gcc doesn't try to be clever and move things around | ||
25 | * on us. We need to use _exactly_ the address the user gave us, | ||
26 | * not some alias that contains the same information. | ||
27 | */ | ||
28 | typedef struct { volatile int counter; } local_t; | ||
29 | |||
30 | #define LOCAL_INIT(i) { (i) } | ||
31 | |||
32 | /** | ||
33 | * local_read - read local variable | ||
34 | * @l: pointer of type local_t | ||
35 | * | ||
36 | * Atomically reads the value of @l. | ||
37 | */ | ||
38 | #define local_read(l) ((l)->counter) | ||
39 | |||
40 | /** | ||
41 | * local_set - set local variable | ||
42 | * @l: pointer of type local_t | ||
43 | * @i: required value | ||
44 | * | ||
45 | * Atomically sets the value of @l to @i. | ||
46 | */ | ||
47 | #define local_set(l, i) (((l)->counter) = (i)) | ||
48 | |||
49 | /** | ||
50 | * local_add_return - add long to local variable and return it | ||
51 | * @i: long value to add | ||
52 | * @l: pointer of type local_t | ||
53 | * | ||
54 | * Atomically adds @i to @l and return (@i + @l). | ||
55 | */ | ||
56 | static inline long local_add_return(long i, local_t *l) | ||
57 | { | ||
58 | unsigned long flags; | ||
59 | long result; | ||
60 | |||
61 | local_irq_save(flags); | ||
62 | __asm__ __volatile__ ( | ||
63 | "# local_add_return \n\t" | ||
64 | DCACHE_CLEAR("%0", "r4", "%1") | ||
65 | "ld %0, @%1; \n\t" | ||
66 | "add %0, %2; \n\t" | ||
67 | "st %0, @%1; \n\t" | ||
68 | : "=&r" (result) | ||
69 | : "r" (&l->counter), "r" (i) | ||
70 | : "memory" | ||
71 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
72 | , "r4" | ||
73 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
74 | ); | ||
75 | local_irq_restore(flags); | ||
76 | |||
77 | return result; | ||
78 | } | ||
79 | |||
80 | /** | ||
81 | * local_sub_return - subtract long from local variable and return it | ||
82 | * @i: long value to subtract | ||
83 | * @l: pointer of type local_t | ||
84 | * | ||
85 | * Atomically subtracts @i from @l and return (@l - @i). | ||
86 | */ | ||
87 | static inline long local_sub_return(long i, local_t *l) | ||
88 | { | ||
89 | unsigned long flags; | ||
90 | long result; | ||
91 | |||
92 | local_irq_save(flags); | ||
93 | __asm__ __volatile__ ( | ||
94 | "# local_sub_return \n\t" | ||
95 | DCACHE_CLEAR("%0", "r4", "%1") | ||
96 | "ld %0, @%1; \n\t" | ||
97 | "sub %0, %2; \n\t" | ||
98 | "st %0, @%1; \n\t" | ||
99 | : "=&r" (result) | ||
100 | : "r" (&l->counter), "r" (i) | ||
101 | : "memory" | ||
102 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
103 | , "r4" | ||
104 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
105 | ); | ||
106 | local_irq_restore(flags); | ||
107 | |||
108 | return result; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * local_add - add long to local variable | ||
113 | * @i: long value to add | ||
114 | * @l: pointer of type local_t | ||
115 | * | ||
116 | * Atomically adds @i to @l. | ||
117 | */ | ||
118 | #define local_add(i, l) ((void) local_add_return((i), (l))) | ||
119 | |||
120 | /** | ||
121 | * local_sub - subtract the local variable | ||
122 | * @i: long value to subtract | ||
123 | * @l: pointer of type local_t | ||
124 | * | ||
125 | * Atomically subtracts @i from @l. | ||
126 | */ | ||
127 | #define local_sub(i, l) ((void) local_sub_return((i), (l))) | ||
128 | |||
129 | /** | ||
130 | * local_sub_and_test - subtract value from variable and test result | ||
131 | * @i: integer value to subtract | ||
132 | * @l: pointer of type local_t | ||
133 | * | ||
134 | * Atomically subtracts @i from @l and returns | ||
135 | * true if the result is zero, or false for all | ||
136 | * other cases. | ||
137 | */ | ||
138 | #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0) | ||
139 | |||
140 | /** | ||
141 | * local_inc_return - increment local variable and return it | ||
142 | * @l: pointer of type local_t | ||
143 | * | ||
144 | * Atomically increments @l by 1 and returns the result. | ||
145 | */ | ||
146 | static inline long local_inc_return(local_t *l) | ||
147 | { | ||
148 | unsigned long flags; | ||
149 | long result; | ||
150 | |||
151 | local_irq_save(flags); | ||
152 | __asm__ __volatile__ ( | ||
153 | "# local_inc_return \n\t" | ||
154 | DCACHE_CLEAR("%0", "r4", "%1") | ||
155 | "ld %0, @%1; \n\t" | ||
156 | "addi %0, #1; \n\t" | ||
157 | "st %0, @%1; \n\t" | ||
158 | : "=&r" (result) | ||
159 | : "r" (&l->counter) | ||
160 | : "memory" | ||
161 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
162 | , "r4" | ||
163 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
164 | ); | ||
165 | local_irq_restore(flags); | ||
166 | |||
167 | return result; | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * local_dec_return - decrement local variable and return it | ||
172 | * @l: pointer of type local_t | ||
173 | * | ||
174 | * Atomically decrements @l by 1 and returns the result. | ||
175 | */ | ||
176 | static inline long local_dec_return(local_t *l) | ||
177 | { | ||
178 | unsigned long flags; | ||
179 | long result; | ||
180 | |||
181 | local_irq_save(flags); | ||
182 | __asm__ __volatile__ ( | ||
183 | "# local_dec_return \n\t" | ||
184 | DCACHE_CLEAR("%0", "r4", "%1") | ||
185 | "ld %0, @%1; \n\t" | ||
186 | "addi %0, #-1; \n\t" | ||
187 | "st %0, @%1; \n\t" | ||
188 | : "=&r" (result) | ||
189 | : "r" (&l->counter) | ||
190 | : "memory" | ||
191 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
192 | , "r4" | ||
193 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
194 | ); | ||
195 | local_irq_restore(flags); | ||
196 | |||
197 | return result; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * local_inc - increment local variable | ||
202 | * @l: pointer of type local_t | ||
203 | * | ||
204 | * Atomically increments @l by 1. | ||
205 | */ | ||
206 | #define local_inc(l) ((void)local_inc_return(l)) | ||
207 | |||
208 | /** | ||
209 | * local_dec - decrement local variable | ||
210 | * @l: pointer of type local_t | ||
211 | * | ||
212 | * Atomically decrements @l by 1. | ||
213 | */ | ||
214 | #define local_dec(l) ((void)local_dec_return(l)) | ||
215 | |||
216 | /** | ||
217 | * local_inc_and_test - increment and test | ||
218 | * @l: pointer of type local_t | ||
219 | * | ||
220 | * Atomically increments @l by 1 | ||
221 | * and returns true if the result is zero, or false for all | ||
222 | * other cases. | ||
223 | */ | ||
224 | #define local_inc_and_test(l) (local_inc_return(l) == 0) | ||
225 | |||
226 | /** | ||
227 | * local_dec_and_test - decrement and test | ||
228 | * @l: pointer of type local_t | ||
229 | * | ||
230 | * Atomically decrements @l by 1 and | ||
231 | * returns true if the result is 0, or false for all | ||
232 | * other cases. | ||
233 | */ | ||
234 | #define local_dec_and_test(l) (local_dec_return(l) == 0) | ||
235 | |||
236 | /** | ||
237 | * local_add_negative - add and test if negative | ||
238 | * @l: pointer of type local_t | ||
239 | * @i: integer value to add | ||
240 | * | ||
241 | * Atomically adds @i to @l and returns true | ||
242 | * if the result is negative, or false when | ||
243 | * result is greater than or equal to zero. | ||
244 | */ | ||
245 | #define local_add_negative(i, l) (local_add_return((i), (l)) < 0) | ||
246 | |||
247 | #define local_cmpxchg(l, o, n) (cmpxchg_local(&((l)->counter), (o), (n))) | ||
248 | #define local_xchg(v, new) (xchg_local(&((l)->counter), new)) | ||
249 | |||
250 | /** | ||
251 | * local_add_unless - add unless the number is a given value | ||
252 | * @l: pointer of type local_t | ||
253 | * @a: the amount to add to l... | ||
254 | * @u: ...unless l is equal to u. | ||
255 | * | ||
256 | * Atomically adds @a to @l, so long as it was not @u. | ||
257 | * Returns non-zero if @l was not @u, and zero otherwise. | ||
258 | */ | ||
259 | static inline int local_add_unless(local_t *l, long a, long u) | ||
260 | { | ||
261 | long c, old; | ||
262 | c = local_read(l); | ||
263 | for (;;) { | ||
264 | if (unlikely(c == (u))) | ||
265 | break; | ||
266 | old = local_cmpxchg((l), c, c + (a)); | ||
267 | if (likely(old == c)) | ||
268 | break; | ||
269 | c = old; | ||
270 | } | ||
271 | return c != (u); | ||
272 | } | ||
273 | |||
274 | #define local_inc_not_zero(l) local_add_unless((l), 1, 0) | ||
275 | |||
276 | static inline void local_clear_mask(unsigned long mask, local_t *addr) | ||
277 | { | ||
278 | unsigned long flags; | ||
279 | unsigned long tmp; | ||
280 | |||
281 | local_irq_save(flags); | ||
282 | __asm__ __volatile__ ( | ||
283 | "# local_clear_mask \n\t" | ||
284 | DCACHE_CLEAR("%0", "r5", "%1") | ||
285 | "ld %0, @%1; \n\t" | ||
286 | "and %0, %2; \n\t" | ||
287 | "st %0, @%1; \n\t" | ||
288 | : "=&r" (tmp) | ||
289 | : "r" (addr), "r" (~mask) | ||
290 | : "memory" | ||
291 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
292 | , "r5" | ||
293 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
294 | ); | ||
295 | local_irq_restore(flags); | ||
296 | } | ||
297 | |||
298 | static inline void local_set_mask(unsigned long mask, local_t *addr) | ||
299 | { | ||
300 | unsigned long flags; | ||
301 | unsigned long tmp; | ||
302 | |||
303 | local_irq_save(flags); | ||
304 | __asm__ __volatile__ ( | ||
305 | "# local_set_mask \n\t" | ||
306 | DCACHE_CLEAR("%0", "r5", "%1") | ||
307 | "ld %0, @%1; \n\t" | ||
308 | "or %0, %2; \n\t" | ||
309 | "st %0, @%1; \n\t" | ||
310 | : "=&r" (tmp) | ||
311 | : "r" (addr), "r" (mask) | ||
312 | : "memory" | ||
313 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
314 | , "r5" | ||
315 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
316 | ); | ||
317 | local_irq_restore(flags); | ||
318 | } | ||
319 | |||
320 | /* Atomic operations are already serializing on m32r */ | ||
321 | #define smp_mb__before_local_dec() barrier() | ||
322 | #define smp_mb__after_local_dec() barrier() | ||
323 | #define smp_mb__before_local_inc() barrier() | ||
324 | #define smp_mb__after_local_inc() barrier() | ||
325 | |||
326 | /* Use these for per-cpu local_t variables: on some archs they are | ||
327 | * much more efficient than these naive implementations. Note they take | ||
328 | * a variable, not an address. | ||
329 | */ | ||
330 | |||
331 | #define __local_inc(l) ((l)->a.counter++) | ||
332 | #define __local_dec(l) ((l)->a.counter++) | ||
333 | #define __local_add(i, l) ((l)->a.counter += (i)) | ||
334 | #define __local_sub(i, l) ((l)->a.counter -= (i)) | ||
335 | |||
336 | /* Use these for per-cpu local_t variables: on some archs they are | ||
337 | * much more efficient than these naive implementations. Note they take | ||
338 | * a variable, not an address. | ||
339 | */ | ||
340 | |||
341 | /* Need to disable preemption for the cpu local counters otherwise we could | ||
342 | still access a variable of a previous CPU in a non local way. */ | ||
343 | #define cpu_local_wrap_v(l) \ | ||
344 | ({ local_t res__; \ | ||
345 | preempt_disable(); \ | ||
346 | res__ = (l); \ | ||
347 | preempt_enable(); \ | ||
348 | res__; }) | ||
349 | #define cpu_local_wrap(l) \ | ||
350 | ({ preempt_disable(); \ | ||
351 | l; \ | ||
352 | preempt_enable(); }) \ | ||
353 | |||
354 | #define cpu_local_read(l) cpu_local_wrap_v(local_read(&__get_cpu_var(l))) | ||
355 | #define cpu_local_set(l, i) cpu_local_wrap(local_set(&__get_cpu_var(l), (i))) | ||
356 | #define cpu_local_inc(l) cpu_local_wrap(local_inc(&__get_cpu_var(l))) | ||
357 | #define cpu_local_dec(l) cpu_local_wrap(local_dec(&__get_cpu_var(l))) | ||
358 | #define cpu_local_add(i, l) cpu_local_wrap(local_add((i), &__get_cpu_var(l))) | ||
359 | #define cpu_local_sub(i, l) cpu_local_wrap(local_sub((i), &__get_cpu_var(l))) | ||
360 | |||
361 | #define __cpu_local_inc(l) cpu_local_inc(l) | ||
362 | #define __cpu_local_dec(l) cpu_local_dec(l) | ||
363 | #define __cpu_local_add(i, l) cpu_local_add((i), (l)) | ||
364 | #define __cpu_local_sub(i, l) cpu_local_sub((i), (l)) | ||
5 | 365 | ||
6 | #endif /* __M32R_LOCAL_H */ | 366 | #endif /* __M32R_LOCAL_H */ |