Merge branches 'msm-fixes' and 'msm-video' of git://codeaurora.org/quic/kernel/dwalke...
[pandora-kernel.git] / arch / mips / include / asm / cmpxchg.h
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2003, 06, 07 by Ralf Baechle (ralf@linux-mips.org)
7  */
8 #ifndef __ASM_CMPXCHG_H
9 #define __ASM_CMPXCHG_H
10
11 #include <linux/irqflags.h>
12
13 #define __HAVE_ARCH_CMPXCHG 1
14
15 #define __cmpxchg_asm(ld, st, m, old, new)                              \
16 ({                                                                      \
17         __typeof(*(m)) __ret;                                           \
18                                                                         \
19         if (kernel_uses_llsc && R10000_LLSC_WAR) {                      \
20                 __asm__ __volatile__(                                   \
21                 "       .set    push                            \n"     \
22                 "       .set    noat                            \n"     \
23                 "       .set    mips3                           \n"     \
24                 "1:     " ld "  %0, %2          # __cmpxchg_asm \n"     \
25                 "       bne     %0, %z3, 2f                     \n"     \
26                 "       .set    mips0                           \n"     \
27                 "       move    $1, %z4                         \n"     \
28                 "       .set    mips3                           \n"     \
29                 "       " st "  $1, %1                          \n"     \
30                 "       beqzl   $1, 1b                          \n"     \
31                 "2:                                             \n"     \
32                 "       .set    pop                             \n"     \
33                 : "=&r" (__ret), "=R" (*m)                              \
34                 : "R" (*m), "Jr" (old), "Jr" (new)                      \
35                 : "memory");                                            \
36         } else if (kernel_uses_llsc) {                                  \
37                 __asm__ __volatile__(                                   \
38                 "       .set    push                            \n"     \
39                 "       .set    noat                            \n"     \
40                 "       .set    mips3                           \n"     \
41                 "1:     " ld "  %0, %2          # __cmpxchg_asm \n"     \
42                 "       bne     %0, %z3, 2f                     \n"     \
43                 "       .set    mips0                           \n"     \
44                 "       move    $1, %z4                         \n"     \
45                 "       .set    mips3                           \n"     \
46                 "       " st "  $1, %1                          \n"     \
47                 "       beqz    $1, 1b                          \n"     \
48                 "       .set    pop                             \n"     \
49                 "2:                                             \n"     \
50                 : "=&r" (__ret), "=R" (*m)                              \
51                 : "R" (*m), "Jr" (old), "Jr" (new)                      \
52                 : "memory");                                            \
53         } else {                                                        \
54                 unsigned long __flags;                                  \
55                                                                         \
56                 raw_local_irq_save(__flags);                            \
57                 __ret = *m;                                             \
58                 if (__ret == old)                                       \
59                         *m = new;                                       \
60                 raw_local_irq_restore(__flags);                         \
61         }                                                               \
62                                                                         \
63         __ret;                                                          \
64 })
65
66 /*
67  * This function doesn't exist, so you'll get a linker error
68  * if something tries to do an invalid cmpxchg().
69  */
70 extern void __cmpxchg_called_with_bad_pointer(void);
71
72 #define __cmpxchg(ptr, old, new, pre_barrier, post_barrier)             \
73 ({                                                                      \
74         __typeof__(ptr) __ptr = (ptr);                                  \
75         __typeof__(*(ptr)) __old = (old);                               \
76         __typeof__(*(ptr)) __new = (new);                               \
77         __typeof__(*(ptr)) __res = 0;                                   \
78                                                                         \
79         pre_barrier;                                                    \
80                                                                         \
81         switch (sizeof(*(__ptr))) {                                     \
82         case 4:                                                         \
83                 __res = __cmpxchg_asm("ll", "sc", __ptr, __old, __new); \
84                 break;                                                  \
85         case 8:                                                         \
86                 if (sizeof(long) == 8) {                                \
87                         __res = __cmpxchg_asm("lld", "scd", __ptr,      \
88                                            __old, __new);               \
89                         break;                                          \
90                 }                                                       \
91         default:                                                        \
92                 __cmpxchg_called_with_bad_pointer();                    \
93                 break;                                                  \
94         }                                                               \
95                                                                         \
96         post_barrier;                                                   \
97                                                                         \
98         __res;                                                          \
99 })
100
101 #define cmpxchg(ptr, old, new)          __cmpxchg(ptr, old, new, smp_mb__before_llsc(), smp_llsc_mb())
102 #define cmpxchg_local(ptr, old, new)    __cmpxchg(ptr, old, new, , )
103
104 #define cmpxchg64(ptr, o, n)                                            \
105   ({                                                                    \
106         BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
107         cmpxchg((ptr), (o), (n));                                       \
108   })
109
110 #ifdef CONFIG_64BIT
111 #define cmpxchg64_local(ptr, o, n)                                      \
112   ({                                                                    \
113         BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
114         cmpxchg_local((ptr), (o), (n));                                 \
115   })
116 #else
117 #include <asm-generic/cmpxchg-local.h>
118 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
119 #endif
120
121 #endif /* __ASM_CMPXCHG_H */