Merge branch 'for-linus' of git://brick.kernel.dk/data/git/linux-2.6-block
[linux-2.6] / include / asm-m68k / atomic.h
1 #ifndef __ARCH_M68K_ATOMIC__
2 #define __ARCH_M68K_ATOMIC__
3
4 #include <linux/config.h>
5
6 #include <asm/system.h> /* local_irq_XXX() */
7
8 /*
9  * Atomic operations that C can't guarantee us.  Useful for
10  * resource counting etc..
11  */
12
13 /*
14  * We do not have SMP m68k systems, so we don't have to deal with that.
15  */
16
17 typedef struct { int counter; } atomic_t;
18 #define ATOMIC_INIT(i)  { (i) }
19
20 #define atomic_read(v)          ((v)->counter)
21 #define atomic_set(v, i)        (((v)->counter) = i)
22
23 static inline void atomic_add(int i, atomic_t *v)
24 {
25         __asm__ __volatile__("addl %1,%0" : "+m" (*v) : "id" (i));
26 }
27
28 static inline void atomic_sub(int i, atomic_t *v)
29 {
30         __asm__ __volatile__("subl %1,%0" : "+m" (*v) : "id" (i));
31 }
32
33 static inline void atomic_inc(atomic_t *v)
34 {
35         __asm__ __volatile__("addql #1,%0" : "+m" (*v));
36 }
37
38 static inline void atomic_dec(atomic_t *v)
39 {
40         __asm__ __volatile__("subql #1,%0" : "+m" (*v));
41 }
42
43 static inline int atomic_dec_and_test(atomic_t *v)
44 {
45         char c;
46         __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "+m" (*v));
47         return c != 0;
48 }
49
50 static inline int atomic_inc_and_test(atomic_t *v)
51 {
52         char c;
53         __asm__ __volatile__("addql #1,%1; seq %0" : "=d" (c), "+m" (*v));
54         return c != 0;
55 }
56
57 #ifdef CONFIG_RMW_INSNS
58
59 static inline int atomic_add_return(int i, atomic_t *v)
60 {
61         int t, tmp;
62
63         __asm__ __volatile__(
64                         "1:     movel %2,%1\n"
65                         "       addl %3,%1\n"
66                         "       casl %2,%1,%0\n"
67                         "       jne 1b"
68                         : "+m" (*v), "=&d" (t), "=&d" (tmp)
69                         : "g" (i), "2" (atomic_read(v)));
70         return t;
71 }
72
73 static inline int atomic_sub_return(int i, atomic_t *v)
74 {
75         int t, tmp;
76
77         __asm__ __volatile__(
78                         "1:     movel %2,%1\n"
79                         "       subl %3,%1\n"
80                         "       casl %2,%1,%0\n"
81                         "       jne 1b"
82                         : "+m" (*v), "=&d" (t), "=&d" (tmp)
83                         : "g" (i), "2" (atomic_read(v)));
84         return t;
85 }
86
87 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
88 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
89
90 #else /* !CONFIG_RMW_INSNS */
91
92 static inline int atomic_add_return(int i, atomic_t * v)
93 {
94         unsigned long flags;
95         int t;
96
97         local_irq_save(flags);
98         t = atomic_read(v);
99         t += i;
100         atomic_set(v, t);
101         local_irq_restore(flags);
102
103         return t;
104 }
105
106 static inline int atomic_sub_return(int i, atomic_t * v)
107 {
108         unsigned long flags;
109         int t;
110
111         local_irq_save(flags);
112         t = atomic_read(v);
113         t -= i;
114         atomic_set(v, t);
115         local_irq_restore(flags);
116
117         return t;
118 }
119
120 static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
121 {
122         unsigned long flags;
123         int prev;
124
125         local_irq_save(flags);
126         prev = atomic_read(v);
127         if (prev == old)
128                 atomic_set(v, new);
129         local_irq_restore(flags);
130         return prev;
131 }
132
133 static inline int atomic_xchg(atomic_t *v, int new)
134 {
135         unsigned long flags;
136         int prev;
137
138         local_irq_save(flags);
139         prev = atomic_read(v);
140         atomic_set(v, new);
141         local_irq_restore(flags);
142         return prev;
143 }
144
145 #endif /* !CONFIG_RMW_INSNS */
146
147 #define atomic_dec_return(v)    atomic_sub_return(1, (v))
148 #define atomic_inc_return(v)    atomic_add_return(1, (v))
149
150 static inline int atomic_sub_and_test(int i, atomic_t *v)
151 {
152         char c;
153         __asm__ __volatile__("subl %2,%1; seq %0" : "=d" (c), "+m" (*v): "g" (i));
154         return c != 0;
155 }
156
157 static inline int atomic_add_negative(int i, atomic_t *v)
158 {
159         char c;
160         __asm__ __volatile__("addl %2,%1; smi %0" : "=d" (c), "+m" (*v): "g" (i));
161         return c != 0;
162 }
163
164 static inline void atomic_clear_mask(unsigned long mask, unsigned long *v)
165 {
166         __asm__ __volatile__("andl %1,%0" : "+m" (*v) : "id" (~(mask)));
167 }
168
169 static inline void atomic_set_mask(unsigned long mask, unsigned long *v)
170 {
171         __asm__ __volatile__("orl %1,%0" : "+m" (*v) : "id" (mask));
172 }
173
174 #define atomic_add_unless(v, a, u)                              \
175 ({                                                              \
176         int c, old;                                             \
177         c = atomic_read(v);                                     \
178         for (;;) {                                              \
179                 if (unlikely(c == (u)))                         \
180                         break;                                  \
181                 old = atomic_cmpxchg((v), c, c + (a));          \
182                 if (likely(old == c))                           \
183                         break;                                  \
184                 c = old;                                        \
185         }                                                       \
186         c != (u);                                               \
187 })
188 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
189
190 /* Atomic operations are already serializing */
191 #define smp_mb__before_atomic_dec()     barrier()
192 #define smp_mb__after_atomic_dec()      barrier()
193 #define smp_mb__before_atomic_inc()     barrier()
194 #define smp_mb__after_atomic_inc()      barrier()
195
196 #include <asm-generic/atomic.h>
197 #endif /* __ARCH_M68K_ATOMIC __ */