xref: /openbmc/linux/arch/arc/include/asm/bitops.h (revision c819e2cf)
1 /*
2  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
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 
9 #ifndef _ASM_BITOPS_H
10 #define _ASM_BITOPS_H
11 
12 #ifndef _LINUX_BITOPS_H
13 #error only <linux/bitops.h> can be included directly
14 #endif
15 
16 #ifndef __ASSEMBLY__
17 
18 #include <linux/types.h>
19 #include <linux/compiler.h>
20 #include <asm/barrier.h>
21 
22 /*
23  * Hardware assisted read-modify-write using ARC700 LLOCK/SCOND insns.
24  * The Kconfig glue ensures that in SMP, this is only set if the container
25  * SoC/platform has cross-core coherent LLOCK/SCOND
26  */
27 #if defined(CONFIG_ARC_HAS_LLSC)
28 
29 static inline void set_bit(unsigned long nr, volatile unsigned long *m)
30 {
31 	unsigned int temp;
32 
33 	m += nr >> 5;
34 
35 	if (__builtin_constant_p(nr))
36 		nr &= 0x1f;
37 
38 	__asm__ __volatile__(
39 	"1:	llock   %0, [%1]	\n"
40 	"	bset    %0, %0, %2	\n"
41 	"	scond   %0, [%1]	\n"
42 	"	bnz     1b	\n"
43 	: "=&r"(temp)
44 	: "r"(m), "ir"(nr)
45 	: "cc");
46 }
47 
48 static inline void clear_bit(unsigned long nr, volatile unsigned long *m)
49 {
50 	unsigned int temp;
51 
52 	m += nr >> 5;
53 
54 	if (__builtin_constant_p(nr))
55 		nr &= 0x1f;
56 
57 	__asm__ __volatile__(
58 	"1:	llock   %0, [%1]	\n"
59 	"	bclr    %0, %0, %2	\n"
60 	"	scond   %0, [%1]	\n"
61 	"	bnz     1b	\n"
62 	: "=&r"(temp)
63 	: "r"(m), "ir"(nr)
64 	: "cc");
65 }
66 
67 static inline void change_bit(unsigned long nr, volatile unsigned long *m)
68 {
69 	unsigned int temp;
70 
71 	m += nr >> 5;
72 
73 	if (__builtin_constant_p(nr))
74 		nr &= 0x1f;
75 
76 	__asm__ __volatile__(
77 	"1:	llock   %0, [%1]	\n"
78 	"	bxor    %0, %0, %2	\n"
79 	"	scond   %0, [%1]	\n"
80 	"	bnz     1b		\n"
81 	: "=&r"(temp)
82 	: "r"(m), "ir"(nr)
83 	: "cc");
84 }
85 
86 /*
87  * Semantically:
88  *    Test the bit
89  *    if clear
90  *        set it and return 0 (old value)
91  *    else
92  *        return 1 (old value).
93  *
94  * Since ARC lacks a equivalent h/w primitive, the bit is set unconditionally
95  * and the old value of bit is returned
96  */
97 static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *m)
98 {
99 	unsigned long old, temp;
100 
101 	m += nr >> 5;
102 
103 	if (__builtin_constant_p(nr))
104 		nr &= 0x1f;
105 
106 	__asm__ __volatile__(
107 	"1:	llock   %0, [%2]	\n"
108 	"	bset    %1, %0, %3	\n"
109 	"	scond   %1, [%2]	\n"
110 	"	bnz     1b		\n"
111 	: "=&r"(old), "=&r"(temp)
112 	: "r"(m), "ir"(nr)
113 	: "cc");
114 
115 	return (old & (1 << nr)) != 0;
116 }
117 
118 static inline int
119 test_and_clear_bit(unsigned long nr, volatile unsigned long *m)
120 {
121 	unsigned int old, temp;
122 
123 	m += nr >> 5;
124 
125 	if (__builtin_constant_p(nr))
126 		nr &= 0x1f;
127 
128 	__asm__ __volatile__(
129 	"1:	llock   %0, [%2]	\n"
130 	"	bclr    %1, %0, %3	\n"
131 	"	scond   %1, [%2]	\n"
132 	"	bnz     1b		\n"
133 	: "=&r"(old), "=&r"(temp)
134 	: "r"(m), "ir"(nr)
135 	: "cc");
136 
137 	return (old & (1 << nr)) != 0;
138 }
139 
140 static inline int
141 test_and_change_bit(unsigned long nr, volatile unsigned long *m)
142 {
143 	unsigned int old, temp;
144 
145 	m += nr >> 5;
146 
147 	if (__builtin_constant_p(nr))
148 		nr &= 0x1f;
149 
150 	__asm__ __volatile__(
151 	"1:	llock   %0, [%2]	\n"
152 	"	bxor    %1, %0, %3	\n"
153 	"	scond   %1, [%2]	\n"
154 	"	bnz     1b		\n"
155 	: "=&r"(old), "=&r"(temp)
156 	: "r"(m), "ir"(nr)
157 	: "cc");
158 
159 	return (old & (1 << nr)) != 0;
160 }
161 
162 #else	/* !CONFIG_ARC_HAS_LLSC */
163 
164 #include <asm/smp.h>
165 
166 /*
167  * Non hardware assisted Atomic-R-M-W
168  * Locking would change to irq-disabling only (UP) and spinlocks (SMP)
169  *
170  * There's "significant" micro-optimization in writing our own variants of
171  * bitops (over generic variants)
172  *
173  * (1) The generic APIs have "signed" @nr while we have it "unsigned"
174  *     This avoids extra code to be generated for pointer arithmatic, since
175  *     is "not sure" that index is NOT -ve
176  * (2) Utilize the fact that ARCompact bit fidding insn (BSET/BCLR/ASL) etc
177  *     only consider bottom 5 bits of @nr, so NO need to mask them off.
178  *     (GCC Quirk: however for constant @nr we still need to do the masking
179  *             at compile time)
180  */
181 
182 static inline void set_bit(unsigned long nr, volatile unsigned long *m)
183 {
184 	unsigned long temp, flags;
185 	m += nr >> 5;
186 
187 	if (__builtin_constant_p(nr))
188 		nr &= 0x1f;
189 
190 	bitops_lock(flags);
191 
192 	temp = *m;
193 	*m = temp | (1UL << nr);
194 
195 	bitops_unlock(flags);
196 }
197 
198 static inline void clear_bit(unsigned long nr, volatile unsigned long *m)
199 {
200 	unsigned long temp, flags;
201 	m += nr >> 5;
202 
203 	if (__builtin_constant_p(nr))
204 		nr &= 0x1f;
205 
206 	bitops_lock(flags);
207 
208 	temp = *m;
209 	*m = temp & ~(1UL << nr);
210 
211 	bitops_unlock(flags);
212 }
213 
214 static inline void change_bit(unsigned long nr, volatile unsigned long *m)
215 {
216 	unsigned long temp, flags;
217 	m += nr >> 5;
218 
219 	if (__builtin_constant_p(nr))
220 		nr &= 0x1f;
221 
222 	bitops_lock(flags);
223 
224 	temp = *m;
225 	*m = temp ^ (1UL << nr);
226 
227 	bitops_unlock(flags);
228 }
229 
230 static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *m)
231 {
232 	unsigned long old, flags;
233 	m += nr >> 5;
234 
235 	if (__builtin_constant_p(nr))
236 		nr &= 0x1f;
237 
238 	bitops_lock(flags);
239 
240 	old = *m;
241 	*m = old | (1 << nr);
242 
243 	bitops_unlock(flags);
244 
245 	return (old & (1 << nr)) != 0;
246 }
247 
248 static inline int
249 test_and_clear_bit(unsigned long nr, volatile unsigned long *m)
250 {
251 	unsigned long old, flags;
252 	m += nr >> 5;
253 
254 	if (__builtin_constant_p(nr))
255 		nr &= 0x1f;
256 
257 	bitops_lock(flags);
258 
259 	old = *m;
260 	*m = old & ~(1 << nr);
261 
262 	bitops_unlock(flags);
263 
264 	return (old & (1 << nr)) != 0;
265 }
266 
267 static inline int
268 test_and_change_bit(unsigned long nr, volatile unsigned long *m)
269 {
270 	unsigned long old, flags;
271 	m += nr >> 5;
272 
273 	if (__builtin_constant_p(nr))
274 		nr &= 0x1f;
275 
276 	bitops_lock(flags);
277 
278 	old = *m;
279 	*m = old ^ (1 << nr);
280 
281 	bitops_unlock(flags);
282 
283 	return (old & (1 << nr)) != 0;
284 }
285 
286 #endif /* CONFIG_ARC_HAS_LLSC */
287 
288 /***************************************
289  * Non atomic variants
290  **************************************/
291 
292 static inline void __set_bit(unsigned long nr, volatile unsigned long *m)
293 {
294 	unsigned long temp;
295 	m += nr >> 5;
296 
297 	if (__builtin_constant_p(nr))
298 		nr &= 0x1f;
299 
300 	temp = *m;
301 	*m = temp | (1UL << nr);
302 }
303 
304 static inline void __clear_bit(unsigned long nr, volatile unsigned long *m)
305 {
306 	unsigned long temp;
307 	m += nr >> 5;
308 
309 	if (__builtin_constant_p(nr))
310 		nr &= 0x1f;
311 
312 	temp = *m;
313 	*m = temp & ~(1UL << nr);
314 }
315 
316 static inline void __change_bit(unsigned long nr, volatile unsigned long *m)
317 {
318 	unsigned long temp;
319 	m += nr >> 5;
320 
321 	if (__builtin_constant_p(nr))
322 		nr &= 0x1f;
323 
324 	temp = *m;
325 	*m = temp ^ (1UL << nr);
326 }
327 
328 static inline int
329 __test_and_set_bit(unsigned long nr, volatile unsigned long *m)
330 {
331 	unsigned long old;
332 	m += nr >> 5;
333 
334 	if (__builtin_constant_p(nr))
335 		nr &= 0x1f;
336 
337 	old = *m;
338 	*m = old | (1 << nr);
339 
340 	return (old & (1 << nr)) != 0;
341 }
342 
343 static inline int
344 __test_and_clear_bit(unsigned long nr, volatile unsigned long *m)
345 {
346 	unsigned long old;
347 	m += nr >> 5;
348 
349 	if (__builtin_constant_p(nr))
350 		nr &= 0x1f;
351 
352 	old = *m;
353 	*m = old & ~(1 << nr);
354 
355 	return (old & (1 << nr)) != 0;
356 }
357 
358 static inline int
359 __test_and_change_bit(unsigned long nr, volatile unsigned long *m)
360 {
361 	unsigned long old;
362 	m += nr >> 5;
363 
364 	if (__builtin_constant_p(nr))
365 		nr &= 0x1f;
366 
367 	old = *m;
368 	*m = old ^ (1 << nr);
369 
370 	return (old & (1 << nr)) != 0;
371 }
372 
373 /*
374  * This routine doesn't need to be atomic.
375  */
376 static inline int
377 __constant_test_bit(unsigned int nr, const volatile unsigned long *addr)
378 {
379 	return ((1UL << (nr & 31)) &
380 		(((const volatile unsigned int *)addr)[nr >> 5])) != 0;
381 }
382 
383 static inline int
384 __test_bit(unsigned int nr, const volatile unsigned long *addr)
385 {
386 	unsigned long mask;
387 
388 	addr += nr >> 5;
389 
390 	/* ARC700 only considers 5 bits in bit-fiddling insn */
391 	mask = 1 << nr;
392 
393 	return ((mask & *addr) != 0);
394 }
395 
396 #define test_bit(nr, addr)	(__builtin_constant_p(nr) ? \
397 					__constant_test_bit((nr), (addr)) : \
398 					__test_bit((nr), (addr)))
399 
400 /*
401  * Count the number of zeros, starting from MSB
402  * Helper for fls( ) friends
403  * This is a pure count, so (1-32) or (0-31) doesn't apply
404  * It could be 0 to 32, based on num of 0's in there
405  * clz(0x8000_0000) = 0, clz(0xFFFF_FFFF)=0, clz(0) = 32, clz(1) = 31
406  */
407 static inline __attribute__ ((const)) int clz(unsigned int x)
408 {
409 	unsigned int res;
410 
411 	__asm__ __volatile__(
412 	"	norm.f  %0, %1		\n"
413 	"	mov.n   %0, 0		\n"
414 	"	add.p   %0, %0, 1	\n"
415 	: "=r"(res)
416 	: "r"(x)
417 	: "cc");
418 
419 	return res;
420 }
421 
422 static inline int constant_fls(int x)
423 {
424 	int r = 32;
425 
426 	if (!x)
427 		return 0;
428 	if (!(x & 0xffff0000u)) {
429 		x <<= 16;
430 		r -= 16;
431 	}
432 	if (!(x & 0xff000000u)) {
433 		x <<= 8;
434 		r -= 8;
435 	}
436 	if (!(x & 0xf0000000u)) {
437 		x <<= 4;
438 		r -= 4;
439 	}
440 	if (!(x & 0xc0000000u)) {
441 		x <<= 2;
442 		r -= 2;
443 	}
444 	if (!(x & 0x80000000u)) {
445 		x <<= 1;
446 		r -= 1;
447 	}
448 	return r;
449 }
450 
451 /*
452  * fls = Find Last Set in word
453  * @result: [1-32]
454  * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0
455  */
456 static inline __attribute__ ((const)) int fls(unsigned long x)
457 {
458 	if (__builtin_constant_p(x))
459 	       return constant_fls(x);
460 
461 	return 32 - clz(x);
462 }
463 
464 /*
465  * __fls: Similar to fls, but zero based (0-31)
466  */
467 static inline __attribute__ ((const)) int __fls(unsigned long x)
468 {
469 	if (!x)
470 		return 0;
471 	else
472 		return fls(x) - 1;
473 }
474 
475 /*
476  * ffs = Find First Set in word (LSB to MSB)
477  * @result: [1-32], 0 if all 0's
478  */
479 #define ffs(x)	({ unsigned long __t = (x); fls(__t & -__t); })
480 
481 /*
482  * __ffs: Similar to ffs, but zero based (0-31)
483  */
484 static inline __attribute__ ((const)) int __ffs(unsigned long word)
485 {
486 	if (!word)
487 		return word;
488 
489 	return ffs(word) - 1;
490 }
491 
492 /*
493  * ffz = Find First Zero in word.
494  * @return:[0-31], 32 if all 1's
495  */
496 #define ffz(x)	__ffs(~(x))
497 
498 #include <asm-generic/bitops/hweight.h>
499 #include <asm-generic/bitops/fls64.h>
500 #include <asm-generic/bitops/sched.h>
501 #include <asm-generic/bitops/lock.h>
502 
503 #include <asm-generic/bitops/find.h>
504 #include <asm-generic/bitops/le.h>
505 #include <asm-generic/bitops/ext2-atomic-setbit.h>
506 
507 #endif /* !__ASSEMBLY__ */
508 
509 #endif
510