Merge branches 'release' and 'throttling-domains' into release
[pandora-kernel.git] / include / asm-frv / bitops.h
1 /* bitops.h: bit operations for the Fujitsu FR-V CPUs
2  *
3  * For an explanation of how atomic ops work in this arch, see:
4  *   Documentation/frv/atomic-ops.txt
5  *
6  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
7  * Written by David Howells (dhowells@redhat.com)
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version
12  * 2 of the License, or (at your option) any later version.
13  */
14 #ifndef _ASM_BITOPS_H
15 #define _ASM_BITOPS_H
16
17 #include <linux/compiler.h>
18 #include <asm/byteorder.h>
19 #include <asm/system.h>
20 #include <asm/atomic.h>
21
22 #ifdef __KERNEL__
23
24 #ifndef _LINUX_BITOPS_H
25 #error only <linux/bitops.h> can be included directly
26 #endif
27
28 #include <asm-generic/bitops/ffz.h>
29
30 /*
31  * clear_bit() doesn't provide any barrier for the compiler.
32  */
33 #define smp_mb__before_clear_bit()      barrier()
34 #define smp_mb__after_clear_bit()       barrier()
35
36 static inline int test_and_clear_bit(int nr, volatile void *addr)
37 {
38         volatile unsigned long *ptr = addr;
39         unsigned long mask = 1UL << (nr & 31);
40         ptr += nr >> 5;
41         return (atomic_test_and_ANDNOT_mask(mask, ptr) & mask) != 0;
42 }
43
44 static inline int test_and_set_bit(int nr, volatile void *addr)
45 {
46         volatile unsigned long *ptr = addr;
47         unsigned long mask = 1UL << (nr & 31);
48         ptr += nr >> 5;
49         return (atomic_test_and_OR_mask(mask, ptr) & mask) != 0;
50 }
51
52 static inline int test_and_change_bit(int nr, volatile void *addr)
53 {
54         volatile unsigned long *ptr = addr;
55         unsigned long mask = 1UL << (nr & 31);
56         ptr += nr >> 5;
57         return (atomic_test_and_XOR_mask(mask, ptr) & mask) != 0;
58 }
59
60 static inline void clear_bit(int nr, volatile void *addr)
61 {
62         test_and_clear_bit(nr, addr);
63 }
64
65 static inline void set_bit(int nr, volatile void *addr)
66 {
67         test_and_set_bit(nr, addr);
68 }
69
70 static inline void change_bit(int nr, volatile void * addr)
71 {
72         test_and_change_bit(nr, addr);
73 }
74
75 static inline void __clear_bit(int nr, volatile void * addr)
76 {
77         volatile unsigned long *a = addr;
78         int mask;
79
80         a += nr >> 5;
81         mask = 1 << (nr & 31);
82         *a &= ~mask;
83 }
84
85 static inline void __set_bit(int nr, volatile void * addr)
86 {
87         volatile unsigned long *a = addr;
88         int mask;
89
90         a += nr >> 5;
91         mask = 1 << (nr & 31);
92         *a |= mask;
93 }
94
95 static inline void __change_bit(int nr, volatile void *addr)
96 {
97         volatile unsigned long *a = addr;
98         int mask;
99
100         a += nr >> 5;
101         mask = 1 << (nr & 31);
102         *a ^= mask;
103 }
104
105 static inline int __test_and_clear_bit(int nr, volatile void * addr)
106 {
107         volatile unsigned long *a = addr;
108         int mask, retval;
109
110         a += nr >> 5;
111         mask = 1 << (nr & 31);
112         retval = (mask & *a) != 0;
113         *a &= ~mask;
114         return retval;
115 }
116
117 static inline int __test_and_set_bit(int nr, volatile void * addr)
118 {
119         volatile unsigned long *a = addr;
120         int mask, retval;
121
122         a += nr >> 5;
123         mask = 1 << (nr & 31);
124         retval = (mask & *a) != 0;
125         *a |= mask;
126         return retval;
127 }
128
129 static inline int __test_and_change_bit(int nr, volatile void * addr)
130 {
131         volatile unsigned long *a = addr;
132         int mask, retval;
133
134         a += nr >> 5;
135         mask = 1 << (nr & 31);
136         retval = (mask & *a) != 0;
137         *a ^= mask;
138         return retval;
139 }
140
141 /*
142  * This routine doesn't need to be atomic.
143  */
144 static inline int __constant_test_bit(int nr, const volatile void * addr)
145 {
146         return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
147 }
148
149 static inline int __test_bit(int nr, const volatile void * addr)
150 {
151         int     * a = (int *) addr;
152         int     mask;
153
154         a += nr >> 5;
155         mask = 1 << (nr & 0x1f);
156         return ((mask & *a) != 0);
157 }
158
159 #define test_bit(nr,addr) \
160 (__builtin_constant_p(nr) ? \
161  __constant_test_bit((nr),(addr)) : \
162  __test_bit((nr),(addr)))
163
164 #include <asm-generic/bitops/find.h>
165
166 /**
167  * fls - find last bit set
168  * @x: the word to search
169  *
170  * This is defined the same way as ffs:
171  * - return 32..1 to indicate bit 31..0 most significant bit set
172  * - return 0 to indicate no bits set
173  */
174 #define fls(x)                                          \
175 ({                                                      \
176         int bit;                                        \
177                                                         \
178         asm("   subcc   %1,gr0,gr0,icc0         \n"     \
179             "   ckne    icc0,cc4                \n"     \
180             "   cscan.p %1,gr0,%0       ,cc4,#1 \n"     \
181             "   csub    %0,%0,%0        ,cc4,#0 \n"     \
182             "   csub    %2,%0,%0        ,cc4,#1 \n"     \
183             : "=&r"(bit)                                \
184             : "r"(x), "r"(32)                           \
185             : "icc0", "cc4"                             \
186             );                                          \
187                                                         \
188         bit;                                            \
189 })
190
191 /**
192  * fls64 - find last bit set in a 64-bit value
193  * @n: the value to search
194  *
195  * This is defined the same way as ffs:
196  * - return 64..1 to indicate bit 63..0 most significant bit set
197  * - return 0 to indicate no bits set
198  */
199 static inline __attribute__((const))
200 int fls64(u64 n)
201 {
202         union {
203                 u64 ll;
204                 struct { u32 h, l; };
205         } _;
206         int bit, x, y;
207
208         _.ll = n;
209
210         asm("   subcc.p         %3,gr0,gr0,icc0         \n"
211             "   subcc           %4,gr0,gr0,icc1         \n"
212             "   ckne            icc0,cc4                \n"
213             "   ckne            icc1,cc5                \n"
214             "   norcr           cc4,cc5,cc6             \n"
215             "   csub.p          %0,%0,%0        ,cc6,1  \n"
216             "   orcr            cc5,cc4,cc4             \n"
217             "   andcr           cc4,cc5,cc4             \n"
218             "   cscan.p         %3,gr0,%0       ,cc4,0  \n"
219             "   setlos          #64,%1                  \n"
220             "   cscan.p         %4,gr0,%0       ,cc4,1  \n"
221             "   setlos          #32,%2                  \n"
222             "   csub.p          %1,%0,%0        ,cc4,0  \n"
223             "   csub            %2,%0,%0        ,cc4,1  \n"
224             : "=&r"(bit), "=r"(x), "=r"(y)
225             : "0r"(_.h), "r"(_.l)
226             : "icc0", "icc1", "cc4", "cc5", "cc6"
227             );
228         return bit;
229
230 }
231
232 /**
233  * ffs - find first bit set
234  * @x: the word to search
235  *
236  * - return 32..1 to indicate bit 31..0 most least significant bit set
237  * - return 0 to indicate no bits set
238  */
239 static inline __attribute__((const))
240 int ffs(int x)
241 {
242         /* Note: (x & -x) gives us a mask that is the least significant
243          * (rightmost) 1-bit of the value in x.
244          */
245         return fls(x & -x);
246 }
247
248 /**
249  * __ffs - find first bit set
250  * @x: the word to search
251  *
252  * - return 31..0 to indicate bit 31..0 most least significant bit set
253  * - if no bits are set in x, the result is undefined
254  */
255 static inline __attribute__((const))
256 int __ffs(unsigned long x)
257 {
258         int bit;
259         asm("scan %1,gr0,%0" : "=r"(bit) : "r"(x & -x));
260         return 31 - bit;
261 }
262
263 /*
264  * special slimline version of fls() for calculating ilog2_u32()
265  * - note: no protection against n == 0
266  */
267 #define ARCH_HAS_ILOG2_U32
268 static inline __attribute__((const))
269 int __ilog2_u32(u32 n)
270 {
271         int bit;
272         asm("scan %1,gr0,%0" : "=r"(bit) : "r"(n));
273         return 31 - bit;
274 }
275
276 /*
277  * special slimline version of fls64() for calculating ilog2_u64()
278  * - note: no protection against n == 0
279  */
280 #define ARCH_HAS_ILOG2_U64
281 static inline __attribute__((const))
282 int __ilog2_u64(u64 n)
283 {
284         union {
285                 u64 ll;
286                 struct { u32 h, l; };
287         } _;
288         int bit, x, y;
289
290         _.ll = n;
291
292         asm("   subcc           %3,gr0,gr0,icc0         \n"
293             "   ckeq            icc0,cc4                \n"
294             "   cscan.p         %3,gr0,%0       ,cc4,0  \n"
295             "   setlos          #63,%1                  \n"
296             "   cscan.p         %4,gr0,%0       ,cc4,1  \n"
297             "   setlos          #31,%2                  \n"
298             "   csub.p          %1,%0,%0        ,cc4,0  \n"
299             "   csub            %2,%0,%0        ,cc4,1  \n"
300             : "=&r"(bit), "=r"(x), "=r"(y)
301             : "0r"(_.h), "r"(_.l)
302             : "icc0", "cc4"
303             );
304         return bit;
305 }
306
307 #include <asm-generic/bitops/sched.h>
308 #include <asm-generic/bitops/hweight.h>
309 #include <asm-generic/bitops/lock.h>
310
311 #include <asm-generic/bitops/ext2-non-atomic.h>
312
313 #define ext2_set_bit_atomic(lock,nr,addr)       test_and_set_bit  ((nr) ^ 0x18, (addr))
314 #define ext2_clear_bit_atomic(lock,nr,addr)     test_and_clear_bit((nr) ^ 0x18, (addr))
315
316 #include <asm-generic/bitops/minix-le.h>
317
318 #endif /* __KERNEL__ */
319
320 #endif /* _ASM_BITOPS_H */