Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[pandora-kernel.git] / include / asm-m32r / bitops.h
1 #ifndef _ASM_M32R_BITOPS_H
2 #define _ASM_M32R_BITOPS_H
3
4 /*
5  *  linux/include/asm-m32r/bitops.h
6  *
7  *  Copyright 1992, Linus Torvalds.
8  *
9  *  M32R version:
10  *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
11  *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
12  */
13
14 #ifndef _LINUX_BITOPS_H
15 #error only <linux/bitops.h> can be included directly
16 #endif
17
18 #include <linux/compiler.h>
19 #include <asm/assembler.h>
20 #include <asm/system.h>
21 #include <asm/byteorder.h>
22 #include <asm/types.h>
23
24 /*
25  * These have to be done with inline assembly: that way the bit-setting
26  * is guaranteed to be atomic. All bit operations return 0 if the bit
27  * was cleared before the operation and != 0 if it was not.
28  *
29  * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
30  */
31
32 /**
33  * set_bit - Atomically set a bit in memory
34  * @nr: the bit to set
35  * @addr: the address to start counting from
36  *
37  * This function is atomic and may not be reordered.  See __set_bit()
38  * if you do not require the atomic guarantees.
39  * Note that @nr may be almost arbitrarily large; this function is not
40  * restricted to acting on a single-word quantity.
41  */
42 static __inline__ void set_bit(int nr, volatile void * addr)
43 {
44         __u32 mask;
45         volatile __u32 *a = addr;
46         unsigned long flags;
47         unsigned long tmp;
48
49         a += (nr >> 5);
50         mask = (1 << (nr & 0x1F));
51
52         local_irq_save(flags);
53         __asm__ __volatile__ (
54                 DCACHE_CLEAR("%0", "r6", "%1")
55                 M32R_LOCK" %0, @%1;             \n\t"
56                 "or     %0, %2;                 \n\t"
57                 M32R_UNLOCK" %0, @%1;           \n\t"
58                 : "=&r" (tmp)
59                 : "r" (a), "r" (mask)
60                 : "memory"
61 #ifdef CONFIG_CHIP_M32700_TS1
62                 , "r6"
63 #endif  /* CONFIG_CHIP_M32700_TS1 */
64         );
65         local_irq_restore(flags);
66 }
67
68 /**
69  * clear_bit - Clears a bit in memory
70  * @nr: Bit to clear
71  * @addr: Address to start counting from
72  *
73  * clear_bit() is atomic and may not be reordered.  However, it does
74  * not contain a memory barrier, so if it is used for locking purposes,
75  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
76  * in order to ensure changes are visible on other processors.
77  */
78 static __inline__ void clear_bit(int nr, volatile void * addr)
79 {
80         __u32 mask;
81         volatile __u32 *a = addr;
82         unsigned long flags;
83         unsigned long tmp;
84
85         a += (nr >> 5);
86         mask = (1 << (nr & 0x1F));
87
88         local_irq_save(flags);
89
90         __asm__ __volatile__ (
91                 DCACHE_CLEAR("%0", "r6", "%1")
92                 M32R_LOCK" %0, @%1;             \n\t"
93                 "and    %0, %2;                 \n\t"
94                 M32R_UNLOCK" %0, @%1;           \n\t"
95                 : "=&r" (tmp)
96                 : "r" (a), "r" (~mask)
97                 : "memory"
98 #ifdef CONFIG_CHIP_M32700_TS1
99                 , "r6"
100 #endif  /* CONFIG_CHIP_M32700_TS1 */
101         );
102         local_irq_restore(flags);
103 }
104
105 #define smp_mb__before_clear_bit()      barrier()
106 #define smp_mb__after_clear_bit()       barrier()
107
108 /**
109  * change_bit - Toggle a bit in memory
110  * @nr: Bit to clear
111  * @addr: Address to start counting from
112  *
113  * change_bit() is atomic and may not be reordered.
114  * Note that @nr may be almost arbitrarily large; this function is not
115  * restricted to acting on a single-word quantity.
116  */
117 static __inline__ void change_bit(int nr, volatile void * addr)
118 {
119         __u32  mask;
120         volatile __u32  *a = addr;
121         unsigned long flags;
122         unsigned long tmp;
123
124         a += (nr >> 5);
125         mask = (1 << (nr & 0x1F));
126
127         local_irq_save(flags);
128         __asm__ __volatile__ (
129                 DCACHE_CLEAR("%0", "r6", "%1")
130                 M32R_LOCK" %0, @%1;             \n\t"
131                 "xor    %0, %2;                 \n\t"
132                 M32R_UNLOCK" %0, @%1;           \n\t"
133                 : "=&r" (tmp)
134                 : "r" (a), "r" (mask)
135                 : "memory"
136 #ifdef CONFIG_CHIP_M32700_TS1
137                 , "r6"
138 #endif  /* CONFIG_CHIP_M32700_TS1 */
139         );
140         local_irq_restore(flags);
141 }
142
143 /**
144  * test_and_set_bit - Set a bit and return its old value
145  * @nr: Bit to set
146  * @addr: Address to count from
147  *
148  * This operation is atomic and cannot be reordered.
149  * It also implies a memory barrier.
150  */
151 static __inline__ int test_and_set_bit(int nr, volatile void * addr)
152 {
153         __u32 mask, oldbit;
154         volatile __u32 *a = addr;
155         unsigned long flags;
156         unsigned long tmp;
157
158         a += (nr >> 5);
159         mask = (1 << (nr & 0x1F));
160
161         local_irq_save(flags);
162         __asm__ __volatile__ (
163                 DCACHE_CLEAR("%0", "%1", "%2")
164                 M32R_LOCK" %0, @%2;             \n\t"
165                 "mv     %1, %0;                 \n\t"
166                 "and    %0, %3;                 \n\t"
167                 "or     %1, %3;                 \n\t"
168                 M32R_UNLOCK" %1, @%2;           \n\t"
169                 : "=&r" (oldbit), "=&r" (tmp)
170                 : "r" (a), "r" (mask)
171                 : "memory"
172         );
173         local_irq_restore(flags);
174
175         return (oldbit != 0);
176 }
177
178 /**
179  * test_and_clear_bit - Clear a bit and return its old value
180  * @nr: Bit to set
181  * @addr: Address to count from
182  *
183  * This operation is atomic and cannot be reordered.
184  * It also implies a memory barrier.
185  */
186 static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
187 {
188         __u32 mask, oldbit;
189         volatile __u32 *a = addr;
190         unsigned long flags;
191         unsigned long tmp;
192
193         a += (nr >> 5);
194         mask = (1 << (nr & 0x1F));
195
196         local_irq_save(flags);
197
198         __asm__ __volatile__ (
199                 DCACHE_CLEAR("%0", "%1", "%3")
200                 M32R_LOCK" %0, @%3;             \n\t"
201                 "mv     %1, %0;                 \n\t"
202                 "and    %0, %2;                 \n\t"
203                 "not    %2, %2;                 \n\t"
204                 "and    %1, %2;                 \n\t"
205                 M32R_UNLOCK" %1, @%3;           \n\t"
206                 : "=&r" (oldbit), "=&r" (tmp), "+r" (mask)
207                 : "r" (a)
208                 : "memory"
209         );
210         local_irq_restore(flags);
211
212         return (oldbit != 0);
213 }
214
215 /**
216  * test_and_change_bit - Change a bit and return its old value
217  * @nr: Bit to set
218  * @addr: Address to count from
219  *
220  * This operation is atomic and cannot be reordered.
221  * It also implies a memory barrier.
222  */
223 static __inline__ int test_and_change_bit(int nr, volatile void * addr)
224 {
225         __u32 mask, oldbit;
226         volatile __u32 *a = addr;
227         unsigned long flags;
228         unsigned long tmp;
229
230         a += (nr >> 5);
231         mask = (1 << (nr & 0x1F));
232
233         local_irq_save(flags);
234         __asm__ __volatile__ (
235                 DCACHE_CLEAR("%0", "%1", "%2")
236                 M32R_LOCK" %0, @%2;             \n\t"
237                 "mv     %1, %0;                 \n\t"
238                 "and    %0, %3;                 \n\t"
239                 "xor    %1, %3;                 \n\t"
240                 M32R_UNLOCK" %1, @%2;           \n\t"
241                 : "=&r" (oldbit), "=&r" (tmp)
242                 : "r" (a), "r" (mask)
243                 : "memory"
244         );
245         local_irq_restore(flags);
246
247         return (oldbit != 0);
248 }
249
250 #include <asm-generic/bitops/non-atomic.h>
251 #include <asm-generic/bitops/ffz.h>
252 #include <asm-generic/bitops/__ffs.h>
253 #include <asm-generic/bitops/fls.h>
254 #include <asm-generic/bitops/fls64.h>
255
256 #ifdef __KERNEL__
257
258 #include <asm-generic/bitops/sched.h>
259 #include <asm-generic/bitops/find.h>
260 #include <asm-generic/bitops/ffs.h>
261 #include <asm-generic/bitops/hweight.h>
262 #include <asm-generic/bitops/lock.h>
263
264 #endif /* __KERNEL__ */
265
266 #ifdef __KERNEL__
267
268 #include <asm-generic/bitops/ext2-non-atomic.h>
269 #include <asm-generic/bitops/ext2-atomic.h>
270 #include <asm-generic/bitops/minix.h>
271
272 #endif /* __KERNEL__ */
273
274 #endif /* _ASM_M32R_BITOPS_H */