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