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