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