• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2004-2006 Atmel Corporation
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8 #ifndef __ASM_AVR32_BITOPS_H
9 #define __ASM_AVR32_BITOPS_H
10 
11 #ifndef _LINUX_BITOPS_H
12 #error only <linux/bitops.h> can be included directly
13 #endif
14 
15 #include <asm/byteorder.h>
16 #include <asm/barrier.h>
17 
18 /*
19  * set_bit - Atomically set a bit in memory
20  * @nr: the bit to set
21  * @addr: the address to start counting from
22  *
23  * This function is atomic and may not be reordered.  See __set_bit()
24  * if you do not require the atomic guarantees.
25  *
26  * Note that @nr may be almost arbitrarily large; this function is not
27  * restricted to acting on a single-word quantity.
28  */
set_bit(int nr,volatile void * addr)29 static inline void set_bit(int nr, volatile void * addr)
30 {
31 	unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
32 	unsigned long tmp;
33 
34 	if (__builtin_constant_p(nr)) {
35 		asm volatile(
36 			"1:	ssrf	5\n"
37 			"	ld.w	%0, %2\n"
38 			"	sbr	%0, %3\n"
39 			"	stcond	%1, %0\n"
40 			"	brne	1b"
41 			: "=&r"(tmp), "=o"(*p)
42 			: "m"(*p), "i"(nr)
43 			: "cc");
44 	} else {
45 		unsigned long mask = 1UL << (nr % BITS_PER_LONG);
46 		asm volatile(
47 			"1:	ssrf	5\n"
48 			"	ld.w	%0, %2\n"
49 			"	or	%0, %3\n"
50 			"	stcond	%1, %0\n"
51 			"	brne	1b"
52 			: "=&r"(tmp), "=o"(*p)
53 			: "m"(*p), "r"(mask)
54 			: "cc");
55 	}
56 }
57 
58 /*
59  * clear_bit - Clears a bit in memory
60  * @nr: Bit to clear
61  * @addr: Address to start counting from
62  *
63  * clear_bit() is atomic and may not be reordered.  However, it does
64  * not contain a memory barrier, so if it is used for locking purposes,
65  * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic()
66  * in order to ensure changes are visible on other processors.
67  */
clear_bit(int nr,volatile void * addr)68 static inline void clear_bit(int nr, volatile void * addr)
69 {
70 	unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
71 	unsigned long tmp;
72 
73 	if (__builtin_constant_p(nr)) {
74 		asm volatile(
75 			"1:	ssrf	5\n"
76 			"	ld.w	%0, %2\n"
77 			"	cbr	%0, %3\n"
78 			"	stcond	%1, %0\n"
79 			"	brne	1b"
80 			: "=&r"(tmp), "=o"(*p)
81 			: "m"(*p), "i"(nr)
82 			: "cc");
83 	} else {
84 		unsigned long mask = 1UL << (nr % BITS_PER_LONG);
85 		asm volatile(
86 			"1:	ssrf	5\n"
87 			"	ld.w	%0, %2\n"
88 			"	andn	%0, %3\n"
89 			"	stcond	%1, %0\n"
90 			"	brne	1b"
91 			: "=&r"(tmp), "=o"(*p)
92 			: "m"(*p), "r"(mask)
93 			: "cc");
94 	}
95 }
96 
97 /*
98  * change_bit - Toggle a bit in memory
99  * @nr: Bit to change
100  * @addr: Address to start counting from
101  *
102  * change_bit() is atomic and may not be reordered.
103  * Note that @nr may be almost arbitrarily large; this function is not
104  * restricted to acting on a single-word quantity.
105  */
change_bit(int nr,volatile void * addr)106 static inline void change_bit(int nr, volatile void * addr)
107 {
108 	unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
109 	unsigned long mask = 1UL << (nr % BITS_PER_LONG);
110 	unsigned long tmp;
111 
112 	asm volatile(
113 		"1:	ssrf	5\n"
114 		"	ld.w	%0, %2\n"
115 		"	eor	%0, %3\n"
116 		"	stcond	%1, %0\n"
117 		"	brne	1b"
118 		: "=&r"(tmp), "=o"(*p)
119 		: "m"(*p), "r"(mask)
120 		: "cc");
121 }
122 
123 /*
124  * test_and_set_bit - Set a bit and return its old value
125  * @nr: Bit to set
126  * @addr: Address to count from
127  *
128  * This operation is atomic and cannot be reordered.
129  * It also implies a memory barrier.
130  */
test_and_set_bit(int nr,volatile void * addr)131 static inline int test_and_set_bit(int nr, volatile void * addr)
132 {
133 	unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
134 	unsigned long mask = 1UL << (nr % BITS_PER_LONG);
135 	unsigned long tmp, old;
136 
137 	if (__builtin_constant_p(nr)) {
138 		asm volatile(
139 			"1:	ssrf	5\n"
140 			"	ld.w	%0, %3\n"
141 			"	mov	%2, %0\n"
142 			"	sbr	%0, %4\n"
143 			"	stcond	%1, %0\n"
144 			"	brne	1b"
145 			: "=&r"(tmp), "=o"(*p), "=&r"(old)
146 			: "m"(*p), "i"(nr)
147 			: "memory", "cc");
148 	} else {
149 		asm volatile(
150 			"1:	ssrf	5\n"
151 			"	ld.w	%2, %3\n"
152 			"	or	%0, %2, %4\n"
153 			"	stcond	%1, %0\n"
154 			"	brne	1b"
155 			: "=&r"(tmp), "=o"(*p), "=&r"(old)
156 			: "m"(*p), "r"(mask)
157 			: "memory", "cc");
158 	}
159 
160 	return (old & mask) != 0;
161 }
162 
163 /*
164  * test_and_clear_bit - Clear a bit and return its old value
165  * @nr: Bit to clear
166  * @addr: Address to count from
167  *
168  * This operation is atomic and cannot be reordered.
169  * It also implies a memory barrier.
170  */
test_and_clear_bit(int nr,volatile void * addr)171 static inline int test_and_clear_bit(int nr, volatile void * addr)
172 {
173 	unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
174 	unsigned long mask = 1UL << (nr % BITS_PER_LONG);
175 	unsigned long tmp, old;
176 
177 	if (__builtin_constant_p(nr)) {
178 		asm volatile(
179 			"1:	ssrf	5\n"
180 			"	ld.w	%0, %3\n"
181 			"	mov	%2, %0\n"
182 			"	cbr	%0, %4\n"
183 			"	stcond	%1, %0\n"
184 			"	brne	1b"
185 			: "=&r"(tmp), "=o"(*p), "=&r"(old)
186 			: "m"(*p), "i"(nr)
187 			: "memory", "cc");
188 	} else {
189 		asm volatile(
190 			"1:	ssrf	5\n"
191 			"	ld.w	%0, %3\n"
192 			"	mov	%2, %0\n"
193 			"	andn	%0, %4\n"
194 			"	stcond	%1, %0\n"
195 			"	brne	1b"
196 			: "=&r"(tmp), "=o"(*p), "=&r"(old)
197 			: "m"(*p), "r"(mask)
198 			: "memory", "cc");
199 	}
200 
201 	return (old & mask) != 0;
202 }
203 
204 /*
205  * test_and_change_bit - Change a bit and return its old value
206  * @nr: Bit to change
207  * @addr: Address to count from
208  *
209  * This operation is atomic and cannot be reordered.
210  * It also implies a memory barrier.
211  */
test_and_change_bit(int nr,volatile void * addr)212 static inline int test_and_change_bit(int nr, volatile void * addr)
213 {
214 	unsigned long *p = ((unsigned long *)addr) + nr / BITS_PER_LONG;
215 	unsigned long mask = 1UL << (nr % BITS_PER_LONG);
216 	unsigned long tmp, old;
217 
218 	asm volatile(
219 		"1:	ssrf	5\n"
220 		"	ld.w	%2, %3\n"
221 		"	eor	%0, %2, %4\n"
222 		"	stcond	%1, %0\n"
223 		"	brne	1b"
224 		: "=&r"(tmp), "=o"(*p), "=&r"(old)
225 		: "m"(*p), "r"(mask)
226 		: "memory", "cc");
227 
228 	return (old & mask) != 0;
229 }
230 
231 #include <asm-generic/bitops/non-atomic.h>
232 
233 /* Find First bit Set */
__ffs(unsigned long word)234 static inline unsigned long __ffs(unsigned long word)
235 {
236 	unsigned long result;
237 
238 	asm("brev %1\n\t"
239 	    "clz %0,%1"
240 	    : "=r"(result), "=&r"(word)
241 	    : "1"(word));
242 	return result;
243 }
244 
245 /* Find First Zero */
ffz(unsigned long word)246 static inline unsigned long ffz(unsigned long word)
247 {
248 	return __ffs(~word);
249 }
250 
251 /* Find Last bit Set */
fls(unsigned long word)252 static inline int fls(unsigned long word)
253 {
254 	unsigned long result;
255 
256 	asm("clz %0,%1" : "=r"(result) : "r"(word));
257 	return 32 - result;
258 }
259 
__fls(unsigned long word)260 static inline int __fls(unsigned long word)
261 {
262 	return fls(word) - 1;
263 }
264 
265 unsigned long find_first_zero_bit(const unsigned long *addr,
266 				  unsigned long size);
267 #define find_first_zero_bit find_first_zero_bit
268 
269 unsigned long find_next_zero_bit(const unsigned long *addr,
270 				 unsigned long size,
271 				 unsigned long offset);
272 #define find_next_zero_bit find_next_zero_bit
273 
274 unsigned long find_first_bit(const unsigned long *addr,
275 			     unsigned long size);
276 #define find_first_bit find_first_bit
277 
278 unsigned long find_next_bit(const unsigned long *addr,
279 				 unsigned long size,
280 				 unsigned long offset);
281 #define find_next_bit find_next_bit
282 
283 /*
284  * ffs: find first bit set. This is defined the same way as
285  * the libc and compiler builtin ffs routines, therefore
286  * differs in spirit from the above ffz (man ffs).
287  *
288  * The difference is that bit numbering starts at 1, and if no bit is set,
289  * the function returns 0.
290  */
ffs(unsigned long word)291 static inline int ffs(unsigned long word)
292 {
293 	if(word == 0)
294 		return 0;
295 	return __ffs(word) + 1;
296 }
297 
298 #include <asm-generic/bitops/fls64.h>
299 #include <asm-generic/bitops/sched.h>
300 #include <asm-generic/bitops/hweight.h>
301 #include <asm-generic/bitops/lock.h>
302 
303 extern unsigned long find_next_zero_bit_le(const void *addr,
304 		unsigned long size, unsigned long offset);
305 #define find_next_zero_bit_le find_next_zero_bit_le
306 
307 extern unsigned long find_next_bit_le(const void *addr,
308 		unsigned long size, unsigned long offset);
309 #define find_next_bit_le find_next_bit_le
310 
311 #include <asm-generic/bitops/le.h>
312 #include <asm-generic/bitops/ext2-atomic.h>
313 
314 #endif /* __ASM_AVR32_BITOPS_H */
315