diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-09-30 23:15:00 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-03 09:30:52 -0400 |
commit | fef74705ea310acd716c2722bfeb0f796cf23640 (patch) | |
tree | 95f48dfc2f53edd15fc5246250444c46fca22010 /include/asm-mips/system.h | |
parent | f6a9e6dec537dc1d9d2c62d7b8ad205d0993bddc (diff) |
[MIPS] Type proof reimplementation of cmpxchg.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'include/asm-mips/system.h')
-rw-r--r-- | include/asm-mips/system.h | 261 |
1 files changed, 1 insertions, 260 deletions
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index 357251f42518..480b574e2483 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <asm/addrspace.h> | 18 | #include <asm/addrspace.h> |
19 | #include <asm/barrier.h> | 19 | #include <asm/barrier.h> |
20 | #include <asm/cmpxchg.h> | ||
20 | #include <asm/cpu-features.h> | 21 | #include <asm/cpu-features.h> |
21 | #include <asm/dsp.h> | 22 | #include <asm/dsp.h> |
22 | #include <asm/war.h> | 23 | #include <asm/war.h> |
@@ -194,266 +195,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz | |||
194 | 195 | ||
195 | #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) | 196 | #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) |
196 | 197 | ||
197 | #define __HAVE_ARCH_CMPXCHG 1 | ||
198 | |||
199 | static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old, | ||
200 | unsigned long new) | ||
201 | { | ||
202 | __u32 retval; | ||
203 | |||
204 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
205 | __asm__ __volatile__( | ||
206 | " .set push \n" | ||
207 | " .set noat \n" | ||
208 | " .set mips3 \n" | ||
209 | "1: ll %0, %2 # __cmpxchg_u32 \n" | ||
210 | " bne %0, %z3, 2f \n" | ||
211 | " .set mips0 \n" | ||
212 | " move $1, %z4 \n" | ||
213 | " .set mips3 \n" | ||
214 | " sc $1, %1 \n" | ||
215 | " beqzl $1, 1b \n" | ||
216 | "2: \n" | ||
217 | " .set pop \n" | ||
218 | : "=&r" (retval), "=R" (*m) | ||
219 | : "R" (*m), "Jr" (old), "Jr" (new) | ||
220 | : "memory"); | ||
221 | } else if (cpu_has_llsc) { | ||
222 | __asm__ __volatile__( | ||
223 | " .set push \n" | ||
224 | " .set noat \n" | ||
225 | " .set mips3 \n" | ||
226 | "1: ll %0, %2 # __cmpxchg_u32 \n" | ||
227 | " bne %0, %z3, 2f \n" | ||
228 | " .set mips0 \n" | ||
229 | " move $1, %z4 \n" | ||
230 | " .set mips3 \n" | ||
231 | " sc $1, %1 \n" | ||
232 | " beqz $1, 3f \n" | ||
233 | "2: \n" | ||
234 | " .subsection 2 \n" | ||
235 | "3: b 1b \n" | ||
236 | " .previous \n" | ||
237 | " .set pop \n" | ||
238 | : "=&r" (retval), "=R" (*m) | ||
239 | : "R" (*m), "Jr" (old), "Jr" (new) | ||
240 | : "memory"); | ||
241 | } else { | ||
242 | unsigned long flags; | ||
243 | |||
244 | raw_local_irq_save(flags); | ||
245 | retval = *m; | ||
246 | if (retval == old) | ||
247 | *m = new; | ||
248 | raw_local_irq_restore(flags); /* implies memory barrier */ | ||
249 | } | ||
250 | |||
251 | smp_llsc_mb(); | ||
252 | |||
253 | return retval; | ||
254 | } | ||
255 | |||
256 | static inline unsigned long __cmpxchg_u32_local(volatile int * m, | ||
257 | unsigned long old, unsigned long new) | ||
258 | { | ||
259 | __u32 retval; | ||
260 | |||
261 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
262 | __asm__ __volatile__( | ||
263 | " .set push \n" | ||
264 | " .set noat \n" | ||
265 | " .set mips3 \n" | ||
266 | "1: ll %0, %2 # __cmpxchg_u32 \n" | ||
267 | " bne %0, %z3, 2f \n" | ||
268 | " .set mips0 \n" | ||
269 | " move $1, %z4 \n" | ||
270 | " .set mips3 \n" | ||
271 | " sc $1, %1 \n" | ||
272 | " beqzl $1, 1b \n" | ||
273 | "2: \n" | ||
274 | " .set pop \n" | ||
275 | : "=&r" (retval), "=R" (*m) | ||
276 | : "R" (*m), "Jr" (old), "Jr" (new) | ||
277 | : "memory"); | ||
278 | } else if (cpu_has_llsc) { | ||
279 | __asm__ __volatile__( | ||
280 | " .set push \n" | ||
281 | " .set noat \n" | ||
282 | " .set mips3 \n" | ||
283 | "1: ll %0, %2 # __cmpxchg_u32 \n" | ||
284 | " bne %0, %z3, 2f \n" | ||
285 | " .set mips0 \n" | ||
286 | " move $1, %z4 \n" | ||
287 | " .set mips3 \n" | ||
288 | " sc $1, %1 \n" | ||
289 | " beqz $1, 1b \n" | ||
290 | "2: \n" | ||
291 | " .set pop \n" | ||
292 | : "=&r" (retval), "=R" (*m) | ||
293 | : "R" (*m), "Jr" (old), "Jr" (new) | ||
294 | : "memory"); | ||
295 | } else { | ||
296 | unsigned long flags; | ||
297 | |||
298 | local_irq_save(flags); | ||
299 | retval = *m; | ||
300 | if (retval == old) | ||
301 | *m = new; | ||
302 | local_irq_restore(flags); /* implies memory barrier */ | ||
303 | } | ||
304 | |||
305 | return retval; | ||
306 | } | ||
307 | |||
308 | #ifdef CONFIG_64BIT | ||
309 | static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old, | ||
310 | unsigned long new) | ||
311 | { | ||
312 | __u64 retval; | ||
313 | |||
314 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
315 | __asm__ __volatile__( | ||
316 | " .set push \n" | ||
317 | " .set noat \n" | ||
318 | " .set mips3 \n" | ||
319 | "1: lld %0, %2 # __cmpxchg_u64 \n" | ||
320 | " bne %0, %z3, 2f \n" | ||
321 | " move $1, %z4 \n" | ||
322 | " scd $1, %1 \n" | ||
323 | " beqzl $1, 1b \n" | ||
324 | "2: \n" | ||
325 | " .set pop \n" | ||
326 | : "=&r" (retval), "=R" (*m) | ||
327 | : "R" (*m), "Jr" (old), "Jr" (new) | ||
328 | : "memory"); | ||
329 | } else if (cpu_has_llsc) { | ||
330 | __asm__ __volatile__( | ||
331 | " .set push \n" | ||
332 | " .set noat \n" | ||
333 | " .set mips3 \n" | ||
334 | "1: lld %0, %2 # __cmpxchg_u64 \n" | ||
335 | " bne %0, %z3, 2f \n" | ||
336 | " move $1, %z4 \n" | ||
337 | " scd $1, %1 \n" | ||
338 | " beqz $1, 3f \n" | ||
339 | "2: \n" | ||
340 | " .subsection 2 \n" | ||
341 | "3: b 1b \n" | ||
342 | " .previous \n" | ||
343 | " .set pop \n" | ||
344 | : "=&r" (retval), "=R" (*m) | ||
345 | : "R" (*m), "Jr" (old), "Jr" (new) | ||
346 | : "memory"); | ||
347 | } else { | ||
348 | unsigned long flags; | ||
349 | |||
350 | raw_local_irq_save(flags); | ||
351 | retval = *m; | ||
352 | if (retval == old) | ||
353 | *m = new; | ||
354 | raw_local_irq_restore(flags); /* implies memory barrier */ | ||
355 | } | ||
356 | |||
357 | smp_llsc_mb(); | ||
358 | |||
359 | return retval; | ||
360 | } | ||
361 | |||
362 | static inline unsigned long __cmpxchg_u64_local(volatile int * m, | ||
363 | unsigned long old, unsigned long new) | ||
364 | { | ||
365 | __u64 retval; | ||
366 | |||
367 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
368 | __asm__ __volatile__( | ||
369 | " .set push \n" | ||
370 | " .set noat \n" | ||
371 | " .set mips3 \n" | ||
372 | "1: lld %0, %2 # __cmpxchg_u64 \n" | ||
373 | " bne %0, %z3, 2f \n" | ||
374 | " move $1, %z4 \n" | ||
375 | " scd $1, %1 \n" | ||
376 | " beqzl $1, 1b \n" | ||
377 | "2: \n" | ||
378 | " .set pop \n" | ||
379 | : "=&r" (retval), "=R" (*m) | ||
380 | : "R" (*m), "Jr" (old), "Jr" (new) | ||
381 | : "memory"); | ||
382 | } else if (cpu_has_llsc) { | ||
383 | __asm__ __volatile__( | ||
384 | " .set push \n" | ||
385 | " .set noat \n" | ||
386 | " .set mips3 \n" | ||
387 | "1: lld %0, %2 # __cmpxchg_u64 \n" | ||
388 | " bne %0, %z3, 2f \n" | ||
389 | " move $1, %z4 \n" | ||
390 | " scd $1, %1 \n" | ||
391 | " beqz $1, 1b \n" | ||
392 | "2: \n" | ||
393 | " .set pop \n" | ||
394 | : "=&r" (retval), "=R" (*m) | ||
395 | : "R" (*m), "Jr" (old), "Jr" (new) | ||
396 | : "memory"); | ||
397 | } else { | ||
398 | unsigned long flags; | ||
399 | |||
400 | local_irq_save(flags); | ||
401 | retval = *m; | ||
402 | if (retval == old) | ||
403 | *m = new; | ||
404 | local_irq_restore(flags); /* implies memory barrier */ | ||
405 | } | ||
406 | |||
407 | return retval; | ||
408 | } | ||
409 | |||
410 | #else | ||
411 | extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels( | ||
412 | volatile int * m, unsigned long old, unsigned long new); | ||
413 | #define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels | ||
414 | extern unsigned long __cmpxchg_u64_local_unsupported_on_32bit_kernels( | ||
415 | volatile int * m, unsigned long old, unsigned long new); | ||
416 | #define __cmpxchg_u64_local __cmpxchg_u64_local_unsupported_on_32bit_kernels | ||
417 | #endif | ||
418 | |||
419 | /* This function doesn't exist, so you'll get a linker error | ||
420 | if something tries to do an invalid cmpxchg(). */ | ||
421 | extern void __cmpxchg_called_with_bad_pointer(void); | ||
422 | |||
423 | static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old, | ||
424 | unsigned long new, int size) | ||
425 | { | ||
426 | switch (size) { | ||
427 | case 4: | ||
428 | return __cmpxchg_u32(ptr, old, new); | ||
429 | case 8: | ||
430 | return __cmpxchg_u64(ptr, old, new); | ||
431 | } | ||
432 | __cmpxchg_called_with_bad_pointer(); | ||
433 | return old; | ||
434 | } | ||
435 | |||
436 | static inline unsigned long __cmpxchg_local(volatile void * ptr, | ||
437 | unsigned long old, unsigned long new, int size) | ||
438 | { | ||
439 | switch (size) { | ||
440 | case 4: | ||
441 | return __cmpxchg_u32_local(ptr, old, new); | ||
442 | case 8: | ||
443 | return __cmpxchg_u64_local(ptr, old, new); | ||
444 | } | ||
445 | __cmpxchg_called_with_bad_pointer(); | ||
446 | return old; | ||
447 | } | ||
448 | |||
449 | #define cmpxchg(ptr,old,new) \ | ||
450 | ((__typeof__(*(ptr)))__cmpxchg((ptr), \ | ||
451 | (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr)))) | ||
452 | |||
453 | #define cmpxchg_local(ptr,old,new) \ | ||
454 | ((__typeof__(*(ptr)))__cmpxchg_local((ptr), \ | ||
455 | (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr)))) | ||
456 | |||
457 | extern void set_handler (unsigned long offset, void *addr, unsigned long len); | 198 | extern void set_handler (unsigned long offset, void *addr, unsigned long len); |
458 | extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len); | 199 | extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len); |
459 | 200 | ||