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 */
29static 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 */
68static 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 */
106static 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 */
131static 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 */
171static 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 */
212static 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 */
234static 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 */
246static inline unsigned long ffz(unsigned long word)
247{
248	return __ffs(~word);
249}
250
251/* Find Last bit Set */
252static 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
260static inline int __fls(unsigned long word)
261{
262	return fls(word) - 1;
263}
264
265unsigned long find_first_zero_bit(const unsigned long *addr,
266				  unsigned long size);
267#define find_first_zero_bit find_first_zero_bit
268
269unsigned 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
274unsigned long find_first_bit(const unsigned long *addr,
275			     unsigned long size);
276#define find_first_bit find_first_bit
277
278unsigned 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 */
291static 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
303extern 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
307extern 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