1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Arm Limited
3 */
4
5 #ifndef _RTE_BITOPS_H_
6 #define _RTE_BITOPS_H_
7
8 /**
9 * @file
10 * Bit Operations
11 *
12 * This file defines a family of APIs for bit operations
13 * without enforcing memory ordering.
14 */
15
16 #include <stdint.h>
17 #include <rte_debug.h>
18 #include <rte_compat.h>
19
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23
24 /**
25 * Get the uint64_t value for a specified bit set.
26 *
27 * @param nr
28 * The bit number in range of 0 to 63.
29 */
30 #define RTE_BIT64(nr) (UINT64_C(1) << (nr))
31
32 /**
33 * Get the uint32_t value for a specified bit set.
34 *
35 * @param nr
36 * The bit number in range of 0 to 31.
37 */
38 #define RTE_BIT32(nr) (UINT32_C(1) << (nr))
39
40 /*------------------------ 32-bit relaxed operations ------------------------*/
41
42 /**
43 * @warning
44 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
45 *
46 * Get the target bit from a 32-bit value without memory ordering.
47 *
48 * @param nr
49 * The target bit to get.
50 * @param addr
51 * The address holding the bit.
52 * @return
53 * The target bit.
54 */
55 __rte_experimental
56 static inline uint32_t
rte_bit_relaxed_get32(unsigned int nr,volatile uint32_t * addr)57 rte_bit_relaxed_get32(unsigned int nr, volatile uint32_t *addr)
58 {
59 RTE_ASSERT(nr < 32);
60
61 uint32_t mask = UINT32_C(1) << nr;
62 return (*addr) & mask;
63 }
64
65 /**
66 * @warning
67 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
68 *
69 * Set the target bit in a 32-bit value to 1 without memory ordering.
70 *
71 * @param nr
72 * The target bit to set.
73 * @param addr
74 * The address holding the bit.
75 */
76 __rte_experimental
77 static inline void
rte_bit_relaxed_set32(unsigned int nr,volatile uint32_t * addr)78 rte_bit_relaxed_set32(unsigned int nr, volatile uint32_t *addr)
79 {
80 RTE_ASSERT(nr < 32);
81
82 uint32_t mask = RTE_BIT32(nr);
83 *addr = (*addr) | mask;
84 }
85
86 /**
87 * @warning
88 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
89 *
90 * Clear the target bit in a 32-bit value to 0 without memory ordering.
91 *
92 * @param nr
93 * The target bit to clear.
94 * @param addr
95 * The address holding the bit.
96 */
97 __rte_experimental
98 static inline void
rte_bit_relaxed_clear32(unsigned int nr,volatile uint32_t * addr)99 rte_bit_relaxed_clear32(unsigned int nr, volatile uint32_t *addr)
100 {
101 RTE_ASSERT(nr < 32);
102
103 uint32_t mask = RTE_BIT32(nr);
104 *addr = (*addr) & (~mask);
105 }
106
107 /**
108 * @warning
109 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
110 *
111 * Return the original bit from a 32-bit value, then set it to 1 without
112 * memory ordering.
113 *
114 * @param nr
115 * The target bit to get and set.
116 * @param addr
117 * The address holding the bit.
118 * @return
119 * The original bit.
120 */
121 __rte_experimental
122 static inline uint32_t
rte_bit_relaxed_test_and_set32(unsigned int nr,volatile uint32_t * addr)123 rte_bit_relaxed_test_and_set32(unsigned int nr, volatile uint32_t *addr)
124 {
125 RTE_ASSERT(nr < 32);
126
127 uint32_t mask = RTE_BIT32(nr);
128 uint32_t val = *addr;
129 *addr = val | mask;
130 return val & mask;
131 }
132
133 /**
134 * @warning
135 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
136 *
137 * Return the original bit from a 32-bit value, then clear it to 0 without
138 * memory ordering.
139 *
140 * @param nr
141 * The target bit to get and clear.
142 * @param addr
143 * The address holding the bit.
144 * @return
145 * The original bit.
146 */
147 __rte_experimental
148 static inline uint32_t
rte_bit_relaxed_test_and_clear32(unsigned int nr,volatile uint32_t * addr)149 rte_bit_relaxed_test_and_clear32(unsigned int nr, volatile uint32_t *addr)
150 {
151 RTE_ASSERT(nr < 32);
152
153 uint32_t mask = RTE_BIT32(nr);
154 uint32_t val = *addr;
155 *addr = val & (~mask);
156 return val & mask;
157 }
158
159 /*------------------------ 64-bit relaxed operations ------------------------*/
160
161 /**
162 * @warning
163 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
164 *
165 * Get the target bit from a 64-bit value without memory ordering.
166 *
167 * @param nr
168 * The target bit to get.
169 * @param addr
170 * The address holding the bit.
171 * @return
172 * The target bit.
173 */
174 __rte_experimental
175 static inline uint64_t
rte_bit_relaxed_get64(unsigned int nr,volatile uint64_t * addr)176 rte_bit_relaxed_get64(unsigned int nr, volatile uint64_t *addr)
177 {
178 RTE_ASSERT(nr < 64);
179
180 uint64_t mask = RTE_BIT64(nr);
181 return (*addr) & mask;
182 }
183
184 /**
185 * @warning
186 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
187 *
188 * Set the target bit in a 64-bit value to 1 without memory ordering.
189 *
190 * @param nr
191 * The target bit to set.
192 * @param addr
193 * The address holding the bit.
194 */
195 __rte_experimental
196 static inline void
rte_bit_relaxed_set64(unsigned int nr,volatile uint64_t * addr)197 rte_bit_relaxed_set64(unsigned int nr, volatile uint64_t *addr)
198 {
199 RTE_ASSERT(nr < 64);
200
201 uint64_t mask = RTE_BIT64(nr);
202 (*addr) = (*addr) | mask;
203 }
204
205 /**
206 * @warning
207 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
208 *
209 * Clear the target bit in a 64-bit value to 0 without memory ordering.
210 *
211 * @param nr
212 * The target bit to clear.
213 * @param addr
214 * The address holding the bit.
215 */
216 __rte_experimental
217 static inline void
rte_bit_relaxed_clear64(unsigned int nr,volatile uint64_t * addr)218 rte_bit_relaxed_clear64(unsigned int nr, volatile uint64_t *addr)
219 {
220 RTE_ASSERT(nr < 64);
221
222 uint64_t mask = RTE_BIT64(nr);
223 *addr = (*addr) & (~mask);
224 }
225
226 /**
227 * @warning
228 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
229 *
230 * Return the original bit from a 64-bit value, then set it to 1 without
231 * memory ordering.
232 *
233 * @param nr
234 * The target bit to get and set.
235 * @param addr
236 * The address holding the bit.
237 * @return
238 * The original bit.
239 */
240 __rte_experimental
241 static inline uint64_t
rte_bit_relaxed_test_and_set64(unsigned int nr,volatile uint64_t * addr)242 rte_bit_relaxed_test_and_set64(unsigned int nr, volatile uint64_t *addr)
243 {
244 RTE_ASSERT(nr < 64);
245
246 uint64_t mask = RTE_BIT64(nr);
247 uint64_t val = *addr;
248 *addr = val | mask;
249 return val;
250 }
251
252 /**
253 * @warning
254 * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
255 *
256 * Return the original bit from a 64-bit value, then clear it to 0 without
257 * memory ordering.
258 *
259 * @param nr
260 * The target bit to get and clear.
261 * @param addr
262 * The address holding the bit.
263 * @return
264 * The original bit.
265 */
266 __rte_experimental
267 static inline uint64_t
rte_bit_relaxed_test_and_clear64(unsigned int nr,volatile uint64_t * addr)268 rte_bit_relaxed_test_and_clear64(unsigned int nr, volatile uint64_t *addr)
269 {
270 RTE_ASSERT(nr < 64);
271
272 uint64_t mask = RTE_BIT64(nr);
273 uint64_t val = *addr;
274 *addr = val & (~mask);
275 return val & mask;
276 }
277
278 #ifdef __cplusplus
279 }
280 #endif
281
282 #endif /* _RTE_BITOPS_H_ */
283