1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /* Copyright (C) 2012 Regents of the University of California */
3 
4 #ifndef ASM__RISCV__BITOPS_H
5 #define ASM__RISCV__BITOPS_H
6 
7 #include <asm/system.h>
8 
9 #if BITOP_BITS_PER_WORD == 64
10 #define __AMO(op)   "amo" #op ".d"
11 #elif BITOP_BITS_PER_WORD == 32
12 #define __AMO(op)   "amo" #op ".w"
13 #else
14 #error "Unexpected BITOP_BITS_PER_WORD"
15 #endif
16 
17 /* Based on linux/arch/include/asm/bitops.h */
18 
19 /*
20  * Non-atomic bit manipulation.
21  *
22  * Implemented using atomics to be interrupt safe. Could alternatively
23  * implement with local interrupt masking.
24  */
25 #define __set_bit(n, p)      set_bit(n, p)
26 #define __clear_bit(n, p)    clear_bit(n, p)
27 
28 #define test_and_op_bit_ord(op, mod, nr, addr, ord)     \
29 ({                                                      \
30     bitop_uint_t res, mask;                             \
31     mask = BITOP_MASK(nr);                              \
32     asm volatile (                                      \
33         __AMO(op) #ord " %0, %2, %1"                    \
34         : "=r" (res), "+A" (addr[BITOP_WORD(nr)])       \
35         : "r" (mod(mask))                               \
36         : "memory");                                    \
37     ((res & mask) != 0);                                \
38 })
39 
40 #define op_bit_ord(op, mod, nr, addr, ord)      \
41     asm volatile (                              \
42         __AMO(op) #ord " zero, %1, %0"          \
43         : "+A" (addr[BITOP_WORD(nr)])           \
44         : "r" (mod(BITOP_MASK(nr)))             \
45         : "memory");
46 
47 #define test_and_op_bit(op, mod, nr, addr)    \
48     test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
49 #define op_bit(op, mod, nr, addr) \
50     op_bit_ord(op, mod, nr, addr, )
51 
52 /* Bitmask modifiers */
53 #define NOP(x)    (x)
54 #define NOT(x)    (~(x))
55 
56 /**
57  * test_and_set_bit - Set a bit and return its old value
58  * @nr: Bit to set
59  * @addr: Address to count from
60  */
test_and_set_bit(int nr,volatile void * p)61 static inline bool test_and_set_bit(int nr, volatile void *p)
62 {
63     volatile bitop_uint_t *addr = p;
64 
65     return test_and_op_bit(or, NOP, nr, addr);
66 }
67 
68 /**
69  * test_and_clear_bit - Clear a bit and return its old value
70  * @nr: Bit to clear
71  * @addr: Address to count from
72  */
test_and_clear_bit(int nr,volatile void * p)73 static inline bool test_and_clear_bit(int nr, volatile void *p)
74 {
75     volatile bitop_uint_t *addr = p;
76 
77     return test_and_op_bit(and, NOT, nr, addr);
78 }
79 
80 /**
81  * test_and_change_bit - Toggle (change) a bit and return its old value
82  * @nr: Bit to change
83  * @addr: Address to count from
84  *
85  * This operation is atomic and cannot be reordered.
86  * It also implies a memory barrier.
87  */
test_and_change_bit(int nr,volatile void * p)88 static inline bool test_and_change_bit(int nr, volatile void *p)
89 {
90     volatile bitop_uint_t *addr = p;
91 
92     return test_and_op_bit(xor, NOP, nr, addr);
93 }
94 
95 /**
96  * set_bit - Atomically set a bit in memory
97  * @nr: the bit to set
98  * @addr: the address to start counting from
99  *
100  * Note that @nr may be almost arbitrarily large; this function is not
101  * restricted to acting on a single-word quantity.
102  */
set_bit(int nr,volatile void * p)103 static inline void set_bit(int nr, volatile void *p)
104 {
105     volatile bitop_uint_t *addr = p;
106 
107     op_bit(or, NOP, nr, addr);
108 }
109 
110 /**
111  * clear_bit - Clears a bit in memory
112  * @nr: Bit to clear
113  * @addr: Address to start counting from
114  */
clear_bit(int nr,volatile void * p)115 static inline void clear_bit(int nr, volatile void *p)
116 {
117     volatile bitop_uint_t *addr = p;
118 
119     op_bit(and, NOT, nr, addr);
120 }
121 
122 #undef test_and_op_bit
123 #undef op_bit
124 #undef NOP
125 #undef NOT
126 #undef __AMO
127 
128 #define arch_ffs(x)     ((x) ? 1 + __builtin_ctz(x) : 0)
129 #define arch_ffsl(x)    ((x) ? 1 + __builtin_ctzl(x) : 0)
130 #define arch_fls(x)     ((x) ? BITS_PER_INT - __builtin_clz(x) : 0)
131 #define arch_flsl(x)    ((x) ? BITS_PER_LONG - __builtin_clzl(x) : 0)
132 
133 #define arch_hweightl(x) __builtin_popcountl(x)
134 
135 #endif /* ASM__RISCV__BITOPS_H */
136 
137 /*
138  * Local variables:
139  * mode: C
140  * c-file-style: "BSD"
141  * c-basic-offset: 4
142  * indent-tabs-mode: nil
143  * End:
144  */
145