blob: 910d5374ce59fb3e160a005b57d9351671443340 [file] [log] [blame]
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001/*
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
Jiri Slaby06245172007-10-18 23:40:26 -070011#ifndef _LINUX_BITOPS_H
12#error only <linux/bitops.h> can be included directly
13#endif
14
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070015#include <asm/byteorder.h>
Peter Zijlstra710adaa2014-03-13 19:00:37 +010016#include <asm/barrier.h>
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070017
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,
Peter Zijlstra710adaa2014-03-13 19:00:37 +010065 * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic()
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070066 * 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
Rusty Russell96b8d4c2009-01-01 10:12:16 +1030260static inline int __fls(unsigned long word)
261{
262 return fls(word) - 1;
263}
264
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700265unsigned long find_first_zero_bit(const unsigned long *addr,
266 unsigned long size);
Akinobu Mitaa2812e12011-05-26 16:26:06 -0700267#define find_first_zero_bit find_first_zero_bit
268
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700269unsigned long find_next_zero_bit(const unsigned long *addr,
270 unsigned long size,
271 unsigned long offset);
Akinobu Mitaa2812e12011-05-26 16:26:06 -0700272#define find_next_zero_bit find_next_zero_bit
273
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700274unsigned long find_first_bit(const unsigned long *addr,
275 unsigned long size);
Akinobu Mitaa2812e12011-05-26 16:26:06 -0700276#define find_first_bit find_first_bit
277
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700278unsigned long find_next_bit(const unsigned long *addr,
279 unsigned long size,
280 unsigned long offset);
Akinobu Mitaa2812e12011-05-26 16:26:06 -0700281#define find_next_bit find_next_bit
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700282
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>
Nick Piggin26333572007-10-18 03:06:39 -0700301#include <asm-generic/bitops/lock.h>
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700302
Akinobu Mitaa2812e12011-05-26 16:26:06 -0700303extern 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
Akinobu Mita861b5ae2011-03-23 16:42:02 -0700311#include <asm-generic/bitops/le.h>
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700312#include <asm-generic/bitops/ext2-atomic.h>
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700313
314#endif /* __ASM_AVR32_BITOPS_H */