~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/include/asm/bitops.h

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * This file is subject to the terms and conditions of the GNU General Public
  3  * License.  See the file "COPYING" in the main directory of this archive
  4  * for more details.
  5  *
  6  * Copyright (c) 1994 - 1997, 99, 2000, 06, 07  Ralf Baechle (ralf@linux-mips.org)
  7  * Copyright (c) 1999, 2000  Silicon Graphics, Inc.
  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 #include <linux/bits.h>
 17 #include <linux/compiler.h>
 18 #include <linux/types.h>
 19 #include <asm/asm.h>
 20 #include <asm/barrier.h>
 21 #include <asm/byteorder.h>              /* sigh ... */
 22 #include <asm/compiler.h>
 23 #include <asm/cpu-features.h>
 24 #include <asm/sgidefs.h>
 25 
 26 #define __bit_op(mem, insn, inputs...) do {                     \
 27         unsigned long __temp;                                   \
 28                                                                 \
 29         asm volatile(                                           \
 30         "       .set            push                    \n"     \
 31         "       .set            " MIPS_ISA_LEVEL "      \n"     \
 32         "       " __SYNC(full, loongson3_war) "         \n"     \
 33         "1:     " __stringify(LONG_LL)  "       %0, %1  \n"     \
 34         "       " insn          "                       \n"     \
 35         "       " __stringify(LONG_SC)  "       %0, %1  \n"     \
 36         "       " __stringify(SC_BEQZ)  "       %0, 1b  \n"     \
 37         "       .set            pop                     \n"     \
 38         : "=&r"(__temp), "+" GCC_OFF_SMALL_ASM()(mem)           \
 39         : inputs                                                \
 40         : __LLSC_CLOBBER);                                      \
 41 } while (0)
 42 
 43 #define __test_bit_op(mem, ll_dst, insn, inputs...) ({          \
 44         unsigned long __orig, __temp;                           \
 45                                                                 \
 46         asm volatile(                                           \
 47         "       .set            push                    \n"     \
 48         "       .set            " MIPS_ISA_LEVEL "      \n"     \
 49         "       " __SYNC(full, loongson3_war) "         \n"     \
 50         "1:     " __stringify(LONG_LL) " "      ll_dst ", %2\n" \
 51         "       " insn          "                       \n"     \
 52         "       " __stringify(LONG_SC)  "       %1, %2  \n"     \
 53         "       " __stringify(SC_BEQZ)  "       %1, 1b  \n"     \
 54         "       .set            pop                     \n"     \
 55         : "=&r"(__orig), "=&r"(__temp),                         \
 56           "+" GCC_OFF_SMALL_ASM()(mem)                          \
 57         : inputs                                                \
 58         : __LLSC_CLOBBER);                                      \
 59                                                                 \
 60         __orig;                                                 \
 61 })
 62 
 63 /*
 64  * These are the "slower" versions of the functions and are in bitops.c.
 65  * These functions call raw_local_irq_{save,restore}().
 66  */
 67 void __mips_set_bit(unsigned long nr, volatile unsigned long *addr);
 68 void __mips_clear_bit(unsigned long nr, volatile unsigned long *addr);
 69 void __mips_change_bit(unsigned long nr, volatile unsigned long *addr);
 70 int __mips_test_and_set_bit_lock(unsigned long nr,
 71                                  volatile unsigned long *addr);
 72 int __mips_test_and_clear_bit(unsigned long nr,
 73                               volatile unsigned long *addr);
 74 int __mips_test_and_change_bit(unsigned long nr,
 75                                volatile unsigned long *addr);
 76 bool __mips_xor_is_negative_byte(unsigned long mask,
 77                 volatile unsigned long *addr);
 78 
 79 /*
 80  * set_bit - Atomically set a bit in memory
 81  * @nr: the bit to set
 82  * @addr: the address to start counting from
 83  *
 84  * This function is atomic and may not be reordered.  See __set_bit()
 85  * if you do not require the atomic guarantees.
 86  * Note that @nr may be almost arbitrarily large; this function is not
 87  * restricted to acting on a single-word quantity.
 88  */
 89 static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
 90 {
 91         volatile unsigned long *m = &addr[BIT_WORD(nr)];
 92         int bit = nr % BITS_PER_LONG;
 93 
 94         if (!kernel_uses_llsc) {
 95                 __mips_set_bit(nr, addr);
 96                 return;
 97         }
 98 
 99         if ((MIPS_ISA_REV >= 2) && __builtin_constant_p(bit) && (bit >= 16)) {
100                 __bit_op(*m, __stringify(LONG_INS) " %0, %3, %2, 1", "i"(bit), "r"(~0));
101                 return;
102         }
103 
104         __bit_op(*m, "or\t%0, %2", "ir"(BIT(bit)));
105 }
106 
107 /*
108  * clear_bit - Clears a bit in memory
109  * @nr: Bit to clear
110  * @addr: Address to start counting from
111  *
112  * clear_bit() is atomic and may not be reordered.  However, it does
113  * not contain a memory barrier, so if it is used for locking purposes,
114  * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic()
115  * in order to ensure changes are visible on other processors.
116  */
117 static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
118 {
119         volatile unsigned long *m = &addr[BIT_WORD(nr)];
120         int bit = nr % BITS_PER_LONG;
121 
122         if (!kernel_uses_llsc) {
123                 __mips_clear_bit(nr, addr);
124                 return;
125         }
126 
127         if ((MIPS_ISA_REV >= 2) && __builtin_constant_p(bit)) {
128                 __bit_op(*m, __stringify(LONG_INS) " %0, $0, %2, 1", "i"(bit));
129                 return;
130         }
131 
132         __bit_op(*m, "and\t%0, %2", "ir"(~BIT(bit)));
133 }
134 
135 /*
136  * clear_bit_unlock - Clears a bit in memory
137  * @nr: Bit to clear
138  * @addr: Address to start counting from
139  *
140  * clear_bit() is atomic and implies release semantics before the memory
141  * operation. It can be used for an unlock.
142  */
143 static inline void clear_bit_unlock(unsigned long nr, volatile unsigned long *addr)
144 {
145         smp_mb__before_atomic();
146         clear_bit(nr, addr);
147 }
148 
149 /*
150  * change_bit - Toggle a bit in memory
151  * @nr: Bit to change
152  * @addr: Address to start counting from
153  *
154  * change_bit() is atomic and may not be reordered.
155  * Note that @nr may be almost arbitrarily large; this function is not
156  * restricted to acting on a single-word quantity.
157  */
158 static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
159 {
160         volatile unsigned long *m = &addr[BIT_WORD(nr)];
161         int bit = nr % BITS_PER_LONG;
162 
163         if (!kernel_uses_llsc) {
164                 __mips_change_bit(nr, addr);
165                 return;
166         }
167 
168         __bit_op(*m, "xor\t%0, %2", "ir"(BIT(bit)));
169 }
170 
171 /*
172  * test_and_set_bit_lock - Set a bit and return its old value
173  * @nr: Bit to set
174  * @addr: Address to count from
175  *
176  * This operation is atomic and implies acquire ordering semantics
177  * after the memory operation.
178  */
179 static inline int test_and_set_bit_lock(unsigned long nr,
180         volatile unsigned long *addr)
181 {
182         volatile unsigned long *m = &addr[BIT_WORD(nr)];
183         int bit = nr % BITS_PER_LONG;
184         unsigned long res, orig;
185 
186         if (!kernel_uses_llsc) {
187                 res = __mips_test_and_set_bit_lock(nr, addr);
188         } else {
189                 orig = __test_bit_op(*m, "%0",
190                                      "or\t%1, %0, %3",
191                                      "ir"(BIT(bit)));
192                 res = (orig & BIT(bit)) != 0;
193         }
194 
195         smp_llsc_mb();
196 
197         return res;
198 }
199 
200 /*
201  * test_and_set_bit - Set a bit and return its old value
202  * @nr: Bit to set
203  * @addr: Address to count from
204  *
205  * This operation is atomic and cannot be reordered.
206  * It also implies a memory barrier.
207  */
208 static inline int test_and_set_bit(unsigned long nr,
209         volatile unsigned long *addr)
210 {
211         smp_mb__before_atomic();
212         return test_and_set_bit_lock(nr, addr);
213 }
214 
215 /*
216  * test_and_clear_bit - Clear a bit and return its old value
217  * @nr: Bit to clear
218  * @addr: Address to count from
219  *
220  * This operation is atomic and cannot be reordered.
221  * It also implies a memory barrier.
222  */
223 static inline int test_and_clear_bit(unsigned long nr,
224         volatile unsigned long *addr)
225 {
226         volatile unsigned long *m = &addr[BIT_WORD(nr)];
227         int bit = nr % BITS_PER_LONG;
228         unsigned long res, orig;
229 
230         smp_mb__before_atomic();
231 
232         if (!kernel_uses_llsc) {
233                 res = __mips_test_and_clear_bit(nr, addr);
234         } else if ((MIPS_ISA_REV >= 2) && __builtin_constant_p(nr)) {
235                 res = __test_bit_op(*m, "%1",
236                                     __stringify(LONG_EXT) " %0, %1, %3, 1;"
237                                     __stringify(LONG_INS) " %1, $0, %3, 1",
238                                     "i"(bit));
239         } else {
240                 orig = __test_bit_op(*m, "%0",
241                                      "or\t%1, %0, %3;"
242                                      "xor\t%1, %1, %3",
243                                      "ir"(BIT(bit)));
244                 res = (orig & BIT(bit)) != 0;
245         }
246 
247         smp_llsc_mb();
248 
249         return res;
250 }
251 
252 /*
253  * test_and_change_bit - Change a bit and return its old value
254  * @nr: Bit to change
255  * @addr: Address to count from
256  *
257  * This operation is atomic and cannot be reordered.
258  * It also implies a memory barrier.
259  */
260 static inline int test_and_change_bit(unsigned long nr,
261         volatile unsigned long *addr)
262 {
263         volatile unsigned long *m = &addr[BIT_WORD(nr)];
264         int bit = nr % BITS_PER_LONG;
265         unsigned long res, orig;
266 
267         smp_mb__before_atomic();
268 
269         if (!kernel_uses_llsc) {
270                 res = __mips_test_and_change_bit(nr, addr);
271         } else {
272                 orig = __test_bit_op(*m, "%0",
273                                      "xor\t%1, %0, %3",
274                                      "ir"(BIT(bit)));
275                 res = (orig & BIT(bit)) != 0;
276         }
277 
278         smp_llsc_mb();
279 
280         return res;
281 }
282 
283 static inline bool xor_unlock_is_negative_byte(unsigned long mask,
284                 volatile unsigned long *p)
285 {
286         unsigned long orig;
287         bool res;
288 
289         smp_mb__before_atomic();
290 
291         if (!kernel_uses_llsc) {
292                 res = __mips_xor_is_negative_byte(mask, p);
293         } else {
294                 orig = __test_bit_op(*p, "%0",
295                                      "xor\t%1, %0, %3",
296                                      "ir"(mask));
297                 res = (orig & BIT(7)) != 0;
298         }
299 
300         smp_llsc_mb();
301 
302         return res;
303 }
304 
305 #undef __bit_op
306 #undef __test_bit_op
307 
308 #include <asm-generic/bitops/non-atomic.h>
309 
310 /*
311  * __clear_bit_unlock - Clears a bit in memory
312  * @nr: Bit to clear
313  * @addr: Address to start counting from
314  *
315  * __clear_bit() is non-atomic and implies release semantics before the memory
316  * operation. It can be used for an unlock if no other CPUs can concurrently
317  * modify other bits in the word.
318  */
319 static inline void __clear_bit_unlock(unsigned long nr, volatile unsigned long *addr)
320 {
321         smp_mb__before_llsc();
322         __clear_bit(nr, addr);
323         nudge_writes();
324 }
325 
326 /*
327  * Return the bit position (0..63) of the most significant 1 bit in a word
328  * Returns -1 if no 1 bit exists
329  */
330 static __always_inline unsigned long __fls(unsigned long word)
331 {
332         int num;
333 
334         if (BITS_PER_LONG == 32 && !__builtin_constant_p(word) &&
335             __builtin_constant_p(cpu_has_clo_clz) && cpu_has_clo_clz) {
336                 __asm__(
337                 "       .set    push                                    \n"
338                 "       .set    "MIPS_ISA_LEVEL"                        \n"
339                 "       clz     %0, %1                                  \n"
340                 "       .set    pop                                     \n"
341                 : "=r" (num)
342                 : "r" (word));
343 
344                 return 31 - num;
345         }
346 
347         if (BITS_PER_LONG == 64 && !__builtin_constant_p(word) &&
348             __builtin_constant_p(cpu_has_mips64) && cpu_has_mips64) {
349                 __asm__(
350                 "       .set    push                                    \n"
351                 "       .set    "MIPS_ISA_LEVEL"                        \n"
352                 "       dclz    %0, %1                                  \n"
353                 "       .set    pop                                     \n"
354                 : "=r" (num)
355                 : "r" (word));
356 
357                 return 63 - num;
358         }
359 
360         num = BITS_PER_LONG - 1;
361 
362 #if BITS_PER_LONG == 64
363         if (!(word & (~0ul << 32))) {
364                 num -= 32;
365                 word <<= 32;
366         }
367 #endif
368         if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
369                 num -= 16;
370                 word <<= 16;
371         }
372         if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
373                 num -= 8;
374                 word <<= 8;
375         }
376         if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
377                 num -= 4;
378                 word <<= 4;
379         }
380         if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
381                 num -= 2;
382                 word <<= 2;
383         }
384         if (!(word & (~0ul << (BITS_PER_LONG-1))))
385                 num -= 1;
386         return num;
387 }
388 
389 /*
390  * __ffs - find first bit in word.
391  * @word: The word to search
392  *
393  * Returns 0..SZLONG-1
394  * Undefined if no bit exists, so code should check against 0 first.
395  */
396 static __always_inline unsigned long __ffs(unsigned long word)
397 {
398         return __fls(word & -word);
399 }
400 
401 /*
402  * fls - find last bit set.
403  * @word: The word to search
404  *
405  * This is defined the same way as ffs.
406  * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
407  */
408 static inline int fls(unsigned int x)
409 {
410         int r;
411 
412         if (!__builtin_constant_p(x) &&
413             __builtin_constant_p(cpu_has_clo_clz) && cpu_has_clo_clz) {
414                 __asm__(
415                 "       .set    push                                    \n"
416                 "       .set    "MIPS_ISA_LEVEL"                        \n"
417                 "       clz     %0, %1                                  \n"
418                 "       .set    pop                                     \n"
419                 : "=r" (x)
420                 : "r" (x));
421 
422                 return 32 - x;
423         }
424 
425         r = 32;
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 #include <asm-generic/bitops/fls64.h>
452 
453 /*
454  * ffs - find first bit set.
455  * @word: The word to search
456  *
457  * This is defined the same way as
458  * the libc and compiler builtin ffs routines, therefore
459  * differs in spirit from the below ffz (man ffs).
460  */
461 static inline int ffs(int word)
462 {
463         if (!word)
464                 return 0;
465 
466         return fls(word & -word);
467 }
468 
469 #include <asm-generic/bitops/ffz.h>
470 
471 #ifdef __KERNEL__
472 
473 #include <asm-generic/bitops/sched.h>
474 
475 #include <asm/arch_hweight.h>
476 #include <asm-generic/bitops/const_hweight.h>
477 
478 #include <asm-generic/bitops/le.h>
479 #include <asm-generic/bitops/ext2-atomic.h>
480 
481 #endif /* __KERNEL__ */
482 
483 #endif /* _ASM_BITOPS_H */
484 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php