Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
[linux-2.6] / 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 (cpu_has_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 (cpu_has_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, 3f                          \n"     \
48                 "2:                                             \n"     \
49                 "       .subsection 2                           \n"     \
50                 "3:     b       1b                              \n"     \
51                 "       .previous                               \n"     \
52                 "       .set    pop                             \n"     \
53                 : "=&r" (__ret), "=R" (*m)                              \
54                 : "R" (*m), "Jr" (old), "Jr" (new)                      \
55                 : "memory");                                            \
56         } else {                                                        \
57                 unsigned long __flags;                                  \
58                                                                         \
59                 raw_local_irq_save(__flags);                            \
60                 __ret = *m;                                             \
61                 if (__ret == old)                                       \
62                         *m = new;                                       \
63                 raw_local_irq_restore(__flags);                         \
64         }                                                               \
65                                                                         \
66         __ret;                                                          \
67 })
68
69 /*
70  * This function doesn't exist, so you'll get a linker error
71  * if something tries to do an invalid cmpxchg().
72  */
73 extern void __cmpxchg_called_with_bad_pointer(void);
74
75 #define __cmpxchg(ptr, old, new, barrier)                               \
76 ({                                                                      \
77         __typeof__(ptr) __ptr = (ptr);                                  \
78         __typeof__(*(ptr)) __old = (old);                               \
79         __typeof__(*(ptr)) __new = (new);                               \
80         __typeof__(*(ptr)) __res = 0;                                   \
81                                                                         \
82         barrier;                                                        \
83                                                                         \
84         switch (sizeof(*(__ptr))) {                                     \
85         case 4:                                                         \
86                 __res = __cmpxchg_asm("ll", "sc", __ptr, __old, __new); \
87                 break;                                                  \
88         case 8:                                                         \
89                 if (sizeof(long) == 8) {                                \
90                         __res = __cmpxchg_asm("lld", "scd", __ptr,      \
91                                            __old, __new);               \
92                         break;                                          \
93                 }                                                       \
94         default:                                                        \
95                 __cmpxchg_called_with_bad_pointer();                    \
96                 break;                                                  \
97         }                                                               \
98                                                                         \
99         barrier;                                                        \
100                                                                         \
101         __res;                                                          \
102 })
103
104 #define cmpxchg(ptr, old, new)          __cmpxchg(ptr, old, new, smp_llsc_mb())
105 #define cmpxchg_local(ptr, old, new)    __cmpxchg(ptr, old, new, )
106
107 #define cmpxchg64(ptr, o, n)                                            \
108   ({                                                                    \
109         BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
110         cmpxchg((ptr), (o), (n));                                       \
111   })
112
113 #ifdef CONFIG_64BIT
114 #define cmpxchg64_local(ptr, o, n)                                      \
115   ({                                                                    \
116         BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
117         cmpxchg_local((ptr), (o), (n));                                 \
118   })
119 #else
120 #include <asm-generic/cmpxchg-local.h>
121 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
122 #endif
123
124 #endif /* __ASM_CMPXCHG_H */