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

TOMOYO Linux Cross Reference
Linux/arch/riscv/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 /* SPDX-License-Identifier: GPL-2.0-only */
  2 /*
  3  * Copyright (C) 2012 Regents of the University of California
  4  */
  5 
  6 #ifndef _ASM_RISCV_BITOPS_H
  7 #define _ASM_RISCV_BITOPS_H
  8 
  9 #ifndef _LINUX_BITOPS_H
 10 #error "Only <linux/bitops.h> can be included directly"
 11 #endif /* _LINUX_BITOPS_H */
 12 
 13 #include <linux/compiler.h>
 14 #include <linux/irqflags.h>
 15 #include <asm/barrier.h>
 16 #include <asm/bitsperlong.h>
 17 
 18 #if !defined(CONFIG_RISCV_ISA_ZBB) || defined(NO_ALTERNATIVE)
 19 #include <asm-generic/bitops/__ffs.h>
 20 #include <asm-generic/bitops/__fls.h>
 21 #include <asm-generic/bitops/ffs.h>
 22 #include <asm-generic/bitops/fls.h>
 23 
 24 #else
 25 #define __HAVE_ARCH___FFS
 26 #define __HAVE_ARCH___FLS
 27 #define __HAVE_ARCH_FFS
 28 #define __HAVE_ARCH_FLS
 29 
 30 #include <asm-generic/bitops/__ffs.h>
 31 #include <asm-generic/bitops/__fls.h>
 32 #include <asm-generic/bitops/ffs.h>
 33 #include <asm-generic/bitops/fls.h>
 34 
 35 #include <asm/alternative-macros.h>
 36 #include <asm/hwcap.h>
 37 
 38 #if (BITS_PER_LONG == 64)
 39 #define CTZW    "ctzw "
 40 #define CLZW    "clzw "
 41 #elif (BITS_PER_LONG == 32)
 42 #define CTZW    "ctz "
 43 #define CLZW    "clz "
 44 #else
 45 #error "Unexpected BITS_PER_LONG"
 46 #endif
 47 
 48 static __always_inline unsigned long variable__ffs(unsigned long word)
 49 {
 50         asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
 51                                       RISCV_ISA_EXT_ZBB, 1)
 52                           : : : : legacy);
 53 
 54         asm volatile (".option push\n"
 55                       ".option arch,+zbb\n"
 56                       "ctz %0, %1\n"
 57                       ".option pop\n"
 58                       : "=r" (word) : "r" (word) :);
 59 
 60         return word;
 61 
 62 legacy:
 63         return generic___ffs(word);
 64 }
 65 
 66 /**
 67  * __ffs - find first set bit in a long word
 68  * @word: The word to search
 69  *
 70  * Undefined if no set bit exists, so code should check against 0 first.
 71  */
 72 #define __ffs(word)                             \
 73         (__builtin_constant_p(word) ?           \
 74          (unsigned long)__builtin_ctzl(word) :  \
 75          variable__ffs(word))
 76 
 77 static __always_inline unsigned long variable__fls(unsigned long word)
 78 {
 79         asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
 80                                       RISCV_ISA_EXT_ZBB, 1)
 81                           : : : : legacy);
 82 
 83         asm volatile (".option push\n"
 84                       ".option arch,+zbb\n"
 85                       "clz %0, %1\n"
 86                       ".option pop\n"
 87                       : "=r" (word) : "r" (word) :);
 88 
 89         return BITS_PER_LONG - 1 - word;
 90 
 91 legacy:
 92         return generic___fls(word);
 93 }
 94 
 95 /**
 96  * __fls - find last set bit in a long word
 97  * @word: the word to search
 98  *
 99  * Undefined if no set bit exists, so code should check against 0 first.
100  */
101 #define __fls(word)                                                     \
102         (__builtin_constant_p(word) ?                                   \
103          (unsigned long)(BITS_PER_LONG - 1 - __builtin_clzl(word)) :    \
104          variable__fls(word))
105 
106 static __always_inline int variable_ffs(int x)
107 {
108         asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
109                                       RISCV_ISA_EXT_ZBB, 1)
110                           : : : : legacy);
111 
112         if (!x)
113                 return 0;
114 
115         asm volatile (".option push\n"
116                       ".option arch,+zbb\n"
117                       CTZW "%0, %1\n"
118                       ".option pop\n"
119                       : "=r" (x) : "r" (x) :);
120 
121         return x + 1;
122 
123 legacy:
124         return generic_ffs(x);
125 }
126 
127 /**
128  * ffs - find first set bit in a word
129  * @x: the word to search
130  *
131  * This is defined the same way as the libc and compiler builtin ffs routines.
132  *
133  * ffs(value) returns 0 if value is 0 or the position of the first set bit if
134  * value is nonzero. The first (least significant) bit is at position 1.
135  */
136 #define ffs(x) (__builtin_constant_p(x) ? __builtin_ffs(x) : variable_ffs(x))
137 
138 static __always_inline int variable_fls(unsigned int x)
139 {
140         asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
141                                       RISCV_ISA_EXT_ZBB, 1)
142                           : : : : legacy);
143 
144         if (!x)
145                 return 0;
146 
147         asm volatile (".option push\n"
148                       ".option arch,+zbb\n"
149                       CLZW "%0, %1\n"
150                       ".option pop\n"
151                       : "=r" (x) : "r" (x) :);
152 
153         return 32 - x;
154 
155 legacy:
156         return generic_fls(x);
157 }
158 
159 /**
160  * fls - find last set bit in a word
161  * @x: the word to search
162  *
163  * This is defined in a similar way as ffs, but returns the position of the most
164  * significant set bit.
165  *
166  * fls(value) returns 0 if value is 0 or the position of the last set bit if
167  * value is nonzero. The last (most significant) bit is at position 32.
168  */
169 #define fls(x)                                                  \
170 ({                                                              \
171         typeof(x) x_ = (x);                                     \
172         __builtin_constant_p(x_) ?                              \
173          ((x_ != 0) ? (32 - __builtin_clz(x_)) : 0)             \
174          :                                                      \
175          variable_fls(x_);                                      \
176 })
177 
178 #endif /* !defined(CONFIG_RISCV_ISA_ZBB) || defined(NO_ALTERNATIVE) */
179 
180 #include <asm-generic/bitops/ffz.h>
181 #include <asm-generic/bitops/fls64.h>
182 #include <asm-generic/bitops/sched.h>
183 
184 #include <asm/arch_hweight.h>
185 
186 #include <asm-generic/bitops/const_hweight.h>
187 
188 #if (BITS_PER_LONG == 64)
189 #define __AMO(op)       "amo" #op ".d"
190 #elif (BITS_PER_LONG == 32)
191 #define __AMO(op)       "amo" #op ".w"
192 #else
193 #error "Unexpected BITS_PER_LONG"
194 #endif
195 
196 #define __test_and_op_bit_ord(op, mod, nr, addr, ord)           \
197 ({                                                              \
198         unsigned long __res, __mask;                            \
199         __mask = BIT_MASK(nr);                                  \
200         __asm__ __volatile__ (                                  \
201                 __AMO(op) #ord " %0, %2, %1"                    \
202                 : "=r" (__res), "+A" (addr[BIT_WORD(nr)])       \
203                 : "r" (mod(__mask))                             \
204                 : "memory");                                    \
205         ((__res & __mask) != 0);                                \
206 })
207 
208 #define __op_bit_ord(op, mod, nr, addr, ord)                    \
209         __asm__ __volatile__ (                                  \
210                 __AMO(op) #ord " zero, %1, %0"                  \
211                 : "+A" (addr[BIT_WORD(nr)])                     \
212                 : "r" (mod(BIT_MASK(nr)))                       \
213                 : "memory");
214 
215 #define __test_and_op_bit(op, mod, nr, addr)                    \
216         __test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
217 #define __op_bit(op, mod, nr, addr)                             \
218         __op_bit_ord(op, mod, nr, addr, )
219 
220 /* Bitmask modifiers */
221 #define __NOP(x)        (x)
222 #define __NOT(x)        (~(x))
223 
224 /**
225  * test_and_set_bit - Set a bit and return its old value
226  * @nr: Bit to set
227  * @addr: Address to count from
228  *
229  * This operation may be reordered on other architectures than x86.
230  */
231 static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
232 {
233         return __test_and_op_bit(or, __NOP, nr, addr);
234 }
235 
236 /**
237  * test_and_clear_bit - Clear a bit and return its old value
238  * @nr: Bit to clear
239  * @addr: Address to count from
240  *
241  * This operation can be reordered on other architectures other than x86.
242  */
243 static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
244 {
245         return __test_and_op_bit(and, __NOT, nr, addr);
246 }
247 
248 /**
249  * test_and_change_bit - Change a bit and return its old value
250  * @nr: Bit to change
251  * @addr: Address to count from
252  *
253  * This operation is atomic and cannot be reordered.
254  * It also implies a memory barrier.
255  */
256 static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
257 {
258         return __test_and_op_bit(xor, __NOP, nr, addr);
259 }
260 
261 /**
262  * set_bit - Atomically set a bit in memory
263  * @nr: the bit to set
264  * @addr: the address to start counting from
265  *
266  * Note: there are no guarantees that this function will not be reordered
267  * on non x86 architectures, so if you are writing portable code,
268  * make sure not to rely on its reordering guarantees.
269  *
270  * Note that @nr may be almost arbitrarily large; this function is not
271  * restricted to acting on a single-word quantity.
272  */
273 static inline void set_bit(int nr, volatile unsigned long *addr)
274 {
275         __op_bit(or, __NOP, nr, addr);
276 }
277 
278 /**
279  * clear_bit - Clears a bit in memory
280  * @nr: Bit to clear
281  * @addr: Address to start counting from
282  *
283  * Note: there are no guarantees that this function will not be reordered
284  * on non x86 architectures, so if you are writing portable code,
285  * make sure not to rely on its reordering guarantees.
286  */
287 static inline void clear_bit(int nr, volatile unsigned long *addr)
288 {
289         __op_bit(and, __NOT, nr, addr);
290 }
291 
292 /**
293  * change_bit - Toggle a bit in memory
294  * @nr: Bit to change
295  * @addr: Address to start counting from
296  *
297  * change_bit()  may be reordered on other architectures than x86.
298  * Note that @nr may be almost arbitrarily large; this function is not
299  * restricted to acting on a single-word quantity.
300  */
301 static inline void change_bit(int nr, volatile unsigned long *addr)
302 {
303         __op_bit(xor, __NOP, nr, addr);
304 }
305 
306 /**
307  * test_and_set_bit_lock - Set a bit and return its old value, for lock
308  * @nr: Bit to set
309  * @addr: Address to count from
310  *
311  * This operation is atomic and provides acquire barrier semantics.
312  * It can be used to implement bit locks.
313  */
314 static inline int test_and_set_bit_lock(
315         unsigned long nr, volatile unsigned long *addr)
316 {
317         return __test_and_op_bit_ord(or, __NOP, nr, addr, .aq);
318 }
319 
320 /**
321  * clear_bit_unlock - Clear a bit in memory, for unlock
322  * @nr: the bit to set
323  * @addr: the address to start counting from
324  *
325  * This operation is atomic and provides release barrier semantics.
326  */
327 static inline void clear_bit_unlock(
328         unsigned long nr, volatile unsigned long *addr)
329 {
330         __op_bit_ord(and, __NOT, nr, addr, .rl);
331 }
332 
333 /**
334  * __clear_bit_unlock - Clear a bit in memory, for unlock
335  * @nr: the bit to set
336  * @addr: the address to start counting from
337  *
338  * This operation is like clear_bit_unlock, however it is not atomic.
339  * It does provide release barrier semantics so it can be used to unlock
340  * a bit lock, however it would only be used if no other CPU can modify
341  * any bits in the memory until the lock is released (a good example is
342  * if the bit lock itself protects access to the other bits in the word).
343  *
344  * On RISC-V systems there seems to be no benefit to taking advantage of the
345  * non-atomic property here: it's a lot more instructions and we still have to
346  * provide release semantics anyway.
347  */
348 static inline void __clear_bit_unlock(
349         unsigned long nr, volatile unsigned long *addr)
350 {
351         clear_bit_unlock(nr, addr);
352 }
353 
354 static inline bool xor_unlock_is_negative_byte(unsigned long mask,
355                 volatile unsigned long *addr)
356 {
357         unsigned long res;
358         __asm__ __volatile__ (
359                 __AMO(xor) ".rl %0, %2, %1"
360                 : "=r" (res), "+A" (*addr)
361                 : "r" (__NOP(mask))
362                 : "memory");
363         return (res & BIT(7)) != 0;
364 }
365 
366 #undef __test_and_op_bit
367 #undef __op_bit
368 #undef __NOP
369 #undef __NOT
370 #undef __AMO
371 
372 #include <asm-generic/bitops/non-atomic.h>
373 #include <asm-generic/bitops/le.h>
374 #include <asm-generic/bitops/ext2-atomic.h>
375 
376 #endif /* _ASM_RISCV_BITOPS_H */
377 

~ [ 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