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