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