Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2015 6WIND S.A.
3 : : * Copyright 2015 Mellanox Technologies, Ltd
4 : : */
5 : :
6 : : #ifndef RTE_PMD_MLX5_UTILS_H_
7 : : #define RTE_PMD_MLX5_UTILS_H_
8 : :
9 : : #include <stddef.h>
10 : : #include <stdint.h>
11 : : #include <stdio.h>
12 : : #include <limits.h>
13 : : #include <errno.h>
14 : :
15 : : #include <rte_spinlock.h>
16 : : #include <rte_rwlock.h>
17 : : #include <rte_memory.h>
18 : : #include <rte_bitmap.h>
19 : :
20 : : #include <mlx5_common.h>
21 : : #include <mlx5_common_utils.h>
22 : :
23 : : #include "mlx5_defs.h"
24 : :
25 : : extern int mlx5_logtype;
26 : :
27 : : #define MLX5_NET_LOG_PREFIX "mlx5_net"
28 : :
29 : : /* Generic printf()-like logging macro with automatic line feed. */
30 : : #define DRV_LOG(level, ...) \
31 : : PMD_DRV_LOG_(level, mlx5_logtype, MLX5_NET_LOG_PREFIX, \
32 : : __VA_ARGS__ PMD_DRV_LOG_STRIP PMD_DRV_LOG_OPAREN, \
33 : : PMD_DRV_LOG_CPAREN)
34 : :
35 : : /* Convenience macros for accessing mbuf fields. */
36 : : #define NEXT(m) ((m)->next)
37 : : #define DATA_LEN(m) ((m)->data_len)
38 : : #define PKT_LEN(m) ((m)->pkt_len)
39 : : #define DATA_OFF(m) ((m)->data_off)
40 : : #define SET_DATA_OFF(m, o) ((m)->data_off = (o))
41 : : #define NB_SEGS(m) ((m)->nb_segs)
42 : : #define PORT(m) ((m)->port)
43 : :
44 : : /* Transpose flags. Useful to convert IBV to DPDK flags. */
45 : : #define TRANSPOSE(val, from, to) \
46 : : (((from) >= (to)) ? \
47 : : (((val) & (from)) / ((from) / (to))) : \
48 : : (((val) & (from)) * ((to) / (from))))
49 : :
50 : : /*
51 : : * For the case which data is linked with sequence increased index, the
52 : : * array table will be more efficient than hash table once need to search
53 : : * one data entry in large numbers of entries. Since the traditional hash
54 : : * tables has fixed table size, when huge numbers of data saved to the hash
55 : : * table, it also comes lots of hash conflict.
56 : : *
57 : : * But simple array table also has fixed size, allocates all the needed
58 : : * memory at once will waste lots of memory. For the case don't know the
59 : : * exactly number of entries will be impossible to allocate the array.
60 : : *
61 : : * Then the multiple level table helps to balance the two disadvantages.
62 : : * Allocate a global high level table with sub table entries at first,
63 : : * the global table contains the sub table entries, and the sub table will
64 : : * be allocated only once the corresponding index entry need to be saved.
65 : : * e.g. for up to 32-bits index, three level table with 10-10-12 splitting,
66 : : * with sequence increased index, the memory grows with every 4K entries.
67 : : *
68 : : * The currently implementation introduces 10-10-12 32-bits splitting
69 : : * Three-Level table to help the cases which have millions of enties to
70 : : * save. The index entries can be addressed directly by the index, no
71 : : * search will be needed.q
72 : : */
73 : :
74 : : /* L3 table global table define. */
75 : : #define MLX5_L3T_GT_OFFSET 22
76 : : #define MLX5_L3T_GT_SIZE (1 << 10)
77 : : #define MLX5_L3T_GT_MASK (MLX5_L3T_GT_SIZE - 1)
78 : :
79 : : /* L3 table middle table define. */
80 : : #define MLX5_L3T_MT_OFFSET 12
81 : : #define MLX5_L3T_MT_SIZE (1 << 10)
82 : : #define MLX5_L3T_MT_MASK (MLX5_L3T_MT_SIZE - 1)
83 : :
84 : : /* L3 table entry table define. */
85 : : #define MLX5_L3T_ET_OFFSET 0
86 : : #define MLX5_L3T_ET_SIZE (1 << 12)
87 : : #define MLX5_L3T_ET_MASK (MLX5_L3T_ET_SIZE - 1)
88 : :
89 : : /* L3 table type. */
90 : : enum mlx5_l3t_type {
91 : : MLX5_L3T_TYPE_WORD = 0,
92 : : MLX5_L3T_TYPE_DWORD,
93 : : MLX5_L3T_TYPE_QWORD,
94 : : MLX5_L3T_TYPE_PTR,
95 : : MLX5_L3T_TYPE_MAX,
96 : : };
97 : :
98 : : struct mlx5_indexed_pool;
99 : :
100 : : /* Generic data struct. */
101 : : union mlx5_l3t_data {
102 : : uint16_t word;
103 : : uint32_t dword;
104 : : uint64_t qword;
105 : : void *ptr;
106 : : };
107 : :
108 : : /* L3 level table data structure. */
109 : : struct mlx5_l3t_level_tbl {
110 : : uint64_t ref_cnt; /* Table ref_cnt. */
111 : : void *tbl[]; /* Table array. */
112 : : };
113 : :
114 : : /* L3 word entry table data structure. */
115 : : struct __rte_packed_begin mlx5_l3t_entry_word {
116 : : uint32_t idx; /* Table index. */
117 : : uint64_t ref_cnt; /* Table ref_cnt. */
118 : : struct {
119 : : uint16_t data;
120 : : uint32_t ref_cnt;
121 : : } entry[MLX5_L3T_ET_SIZE]; /* Entry array */
122 : : } __rte_packed_end;
123 : :
124 : : /* L3 double word entry table data structure. */
125 : : struct __rte_packed_begin mlx5_l3t_entry_dword {
126 : : uint32_t idx; /* Table index. */
127 : : uint64_t ref_cnt; /* Table ref_cnt. */
128 : : struct {
129 : : uint32_t data;
130 : : int32_t ref_cnt;
131 : : } entry[MLX5_L3T_ET_SIZE]; /* Entry array */
132 : : } __rte_packed_end;
133 : :
134 : : /* L3 quad word entry table data structure. */
135 : : struct __rte_packed_begin mlx5_l3t_entry_qword {
136 : : uint32_t idx; /* Table index. */
137 : : uint64_t ref_cnt; /* Table ref_cnt. */
138 : : struct {
139 : : uint64_t data;
140 : : uint32_t ref_cnt;
141 : : } entry[MLX5_L3T_ET_SIZE]; /* Entry array */
142 : : } __rte_packed_end;
143 : :
144 : : /* L3 pointer entry table data structure. */
145 : : struct __rte_packed_begin mlx5_l3t_entry_ptr {
146 : : uint32_t idx; /* Table index. */
147 : : uint64_t ref_cnt; /* Table ref_cnt. */
148 : : struct {
149 : : void *data;
150 : : uint32_t ref_cnt;
151 : : } entry[MLX5_L3T_ET_SIZE]; /* Entry array */
152 : : } __rte_packed_end;
153 : :
154 : : /* L3 table data structure. */
155 : : struct mlx5_l3t_tbl {
156 : : enum mlx5_l3t_type type; /* Table type. */
157 : : struct mlx5_indexed_pool *eip;
158 : : /* Table index pool handles. */
159 : : struct mlx5_l3t_level_tbl *tbl; /* Global table index. */
160 : : rte_spinlock_t sl; /* The table lock. */
161 : : };
162 : :
163 : : /** Type of function that is used to handle the data before freeing. */
164 : : typedef int32_t (*mlx5_l3t_alloc_callback_fn)(void *ctx,
165 : : union mlx5_l3t_data *data);
166 : :
167 : : /*
168 : : * The default ipool threshold value indicates which per_core_cache
169 : : * value to set.
170 : : */
171 : : #define MLX5_HW_IPOOL_SIZE_THRESHOLD (1 << 19)
172 : : /* The default min local cache size. */
173 : : #define MLX5_HW_IPOOL_CACHE_MIN (1 << 9)
174 : :
175 : : /*
176 : : * The indexed memory entry index is made up of trunk index and offset of
177 : : * the entry in the trunk. Since the entry index is 32 bits, in case user
178 : : * prefers to have small trunks, user can change the macro below to a big
179 : : * number which helps the pool contains more trunks with lots of entries
180 : : * allocated.
181 : : */
182 : : #define TRUNK_IDX_BITS 16
183 : : #define TRUNK_MAX_IDX ((1 << TRUNK_IDX_BITS) - 1)
184 : : #define TRUNK_INVALID TRUNK_MAX_IDX
185 : : #define MLX5_IPOOL_DEFAULT_TRUNK_SIZE (1 << (28 - TRUNK_IDX_BITS))
186 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
187 : : #define POOL_DEBUG 1
188 : : #endif
189 : :
190 : : extern int mlx5_logtype_ipool;
191 : : #define MLX5_NET_LOG_PREFIX_IPOOL "mlx5_ipool"
192 : :
193 : : /* Generic printf()-like logging macro with automatic line feed. */
194 : : #define DRV_LOG_IPOOL(level, ...) \
195 : : PMD_DRV_LOG_(level, mlx5_logtype_ipool, MLX5_NET_LOG_PREFIX_IPOOL, \
196 : : __VA_ARGS__ PMD_DRV_LOG_STRIP PMD_DRV_LOG_OPAREN, \
197 : : PMD_DRV_LOG_CPAREN)
198 : :
199 : : struct mlx5_indexed_pool_config {
200 : : uint32_t size; /* Pool entry size. */
201 : : uint32_t trunk_size:22;
202 : : /*
203 : : * Trunk entry number. Must be power of 2. It can be increased
204 : : * if trunk_grow enable. The trunk entry number increases with
205 : : * left shift grow_shift. Trunks with index are after grow_trunk
206 : : * will keep the entry number same with the last grow trunk.
207 : : */
208 : : uint32_t grow_trunk:4;
209 : : /*
210 : : * Trunks with entry number increase in the pool. Set it to 0
211 : : * to make the pool works as trunk entry fixed pool. It works
212 : : * only if grow_shift is not 0.
213 : : */
214 : : uint32_t grow_shift:4;
215 : : /*
216 : : * Trunk entry number increase shift value, stop after grow_trunk.
217 : : * It works only if grow_trunk is not 0.
218 : : */
219 : : uint32_t need_lock:1;
220 : : /* Lock is needed for multiple thread usage. */
221 : : uint32_t release_mem_en:1; /* Release trunk when it is free. */
222 : : uint32_t max_idx; /* The maximum index can be allocated. */
223 : : uint32_t per_core_cache;
224 : : /*
225 : : * Cache entry number per core for performance. Should not be
226 : : * set with release_mem_en.
227 : : */
228 : : const char *type; /* Memory allocate type name. */
229 : : void *(*malloc)(uint32_t flags, size_t size, unsigned int align,
230 : : int socket);
231 : : /* User defined memory allocator. */
232 : : void (*free)(void *addr); /* User defined memory release. */
233 : : };
234 : :
235 : : struct mlx5_indexed_trunk {
236 : : uint32_t idx; /* Trunk id. */
237 : : uint32_t prev; /* Previous free trunk in free list. */
238 : : uint32_t next; /* Next free trunk in free list. */
239 : : uint32_t free; /* Free entries available */
240 : : struct rte_bitmap *bmp;
241 : : alignas(RTE_CACHE_LINE_SIZE) uint8_t data[]; /* Entry data start. */
242 : : };
243 : :
244 : : struct mlx5_indexed_cache {
245 : : struct mlx5_indexed_trunk **trunks;
246 : : volatile RTE_ATOMIC(uint32_t) n_trunk_valid; /* Trunks allocated. */
247 : : uint32_t n_trunk; /* Trunk pointer array size. */
248 : : uint32_t ref_cnt;
249 : : uint32_t len;
250 : : uint32_t idx[];
251 : : };
252 : :
253 : : struct mlx5_ipool_per_lcore {
254 : : struct mlx5_indexed_cache *lc;
255 : : uint32_t len; /**< Current cache count. */
256 : : uint32_t idx[]; /**< Cache objects. */
257 : : };
258 : :
259 : : #ifdef POOL_DEBUG
260 : : struct mlx5_ipool_cache_validation {
261 : : rte_spinlock_t lock;
262 : : uint32_t bmp_size;
263 : : struct rte_bitmap *bmp;
264 : : void *bmp_mem;
265 : : };
266 : : #endif
267 : :
268 : : struct mlx5_indexed_pool {
269 : : struct mlx5_indexed_pool_config cfg; /* Indexed pool configuration. */
270 : : rte_spinlock_t rsz_lock; /* Pool lock for multiple thread usage. */
271 : : rte_spinlock_t lcore_lock;
272 : : /* Dim of trunk pointer array. */
273 : : union {
274 : : struct {
275 : : uint32_t n_trunk_valid; /* Trunks allocated. */
276 : : uint32_t n_trunk; /* Trunk pointer array size. */
277 : : struct mlx5_indexed_trunk **trunks;
278 : : uint32_t free_list; /* Index to first free trunk. */
279 : : };
280 : : struct {
281 : : RTE_ATOMIC(struct mlx5_indexed_cache *) gc;
282 : : /* Global cache. */
283 : : struct mlx5_ipool_per_lcore *cache[RTE_MAX_LCORE + 1];
284 : : /* Local cache. */
285 : : struct rte_bitmap *ibmp;
286 : : void *bmp_mem;
287 : : /* Allocate objects bitmap. Use during flush. */
288 : : #ifdef POOL_DEBUG
289 : : struct mlx5_ipool_cache_validation cache_validator;
290 : : #endif
291 : : };
292 : : };
293 : : #ifdef POOL_DEBUG
294 : : uint32_t n_entry;
295 : : uint32_t trunk_new;
296 : : uint32_t trunk_avail;
297 : : uint32_t trunk_empty;
298 : : uint32_t trunk_free;
299 : : #endif
300 : : uint32_t grow_tbl[]; /* Save the index offset for the grow trunks. */
301 : : };
302 : :
303 : : /**
304 : : * Return logarithm of the nearest power of two above input value.
305 : : *
306 : : * @param v
307 : : * Input value.
308 : : *
309 : : * @return
310 : : * Logarithm of the nearest power of two above input value.
311 : : */
312 : : static inline unsigned int
313 : : log2above(unsigned int v)
314 : : {
315 : : unsigned int l;
316 : : unsigned int r;
317 : :
318 [ # # # # : 0 : for (l = 0, r = 0; (v >> 1); ++l, v >>= 1)
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
319 : 0 : r |= (v & 1);
320 [ # # # # : 0 : return l + r;
# # ]
321 : : }
322 : :
323 : : /********************************* indexed pool *************************/
324 : :
325 : : /**
326 : : * This function allocates non-initialized memory entry from pool.
327 : : * In NUMA systems, the memory entry allocated resides on the same
328 : : * NUMA socket as the core that calls this function.
329 : : *
330 : : * Memory entry is allocated from memory trunk, no alignment.
331 : : *
332 : : * @param pool
333 : : * Pointer to indexed memory entry pool.
334 : : * No initialization required.
335 : : * @param[out] idx
336 : : * Pointer to memory to save allocated index.
337 : : * Memory index always positive value.
338 : : * @return
339 : : * - Pointer to the allocated memory entry.
340 : : * - NULL on error. Not enough memory, or invalid arguments.
341 : : */
342 : : void *mlx5_ipool_malloc(struct mlx5_indexed_pool *pool, uint32_t *idx);
343 : :
344 : : /**
345 : : * This function allocates zero initialized memory entry from pool.
346 : : * In NUMA systems, the memory entry allocated resides on the same
347 : : * NUMA socket as the core that calls this function.
348 : : *
349 : : * Memory entry is allocated from memory trunk, no alignment.
350 : : *
351 : : * @param pool
352 : : * Pointer to indexed memory pool.
353 : : * No initialization required.
354 : : * @param[out] idx
355 : : * Pointer to memory to save allocated index.
356 : : * Memory index always positive value.
357 : : * @return
358 : : * - Pointer to the allocated memory entry .
359 : : * - NULL on error. Not enough memory, or invalid arguments.
360 : : */
361 : : void *mlx5_ipool_zmalloc(struct mlx5_indexed_pool *pool, uint32_t *idx);
362 : :
363 : : /**
364 : : * This function frees indexed memory entry to pool.
365 : : * Caller has to make sure that the index is allocated from same pool.
366 : : *
367 : : * @param pool
368 : : * Pointer to indexed memory pool.
369 : : * @param idx
370 : : * Allocated memory entry index.
371 : : */
372 : : void mlx5_ipool_free(struct mlx5_indexed_pool *pool, uint32_t idx);
373 : :
374 : : /**
375 : : * This function returns pointer of indexed memory entry from index.
376 : : * Caller has to make sure that the index is valid, and allocated
377 : : * from same pool.
378 : : *
379 : : * @param pool
380 : : * Pointer to indexed memory pool.
381 : : * @param idx
382 : : * Allocated memory index.
383 : : * @return
384 : : * - Pointer to indexed memory entry.
385 : : */
386 : : void *mlx5_ipool_get(struct mlx5_indexed_pool *pool, uint32_t idx);
387 : :
388 : : /**
389 : : * This function creates indexed memory pool.
390 : : * Caller has to configure the configuration accordingly.
391 : : *
392 : : * @param pool
393 : : * Pointer to indexed memory pool.
394 : : * @param cfg
395 : : * Allocated memory index.
396 : : */
397 : : struct mlx5_indexed_pool *
398 : : mlx5_ipool_create(struct mlx5_indexed_pool_config *cfg);
399 : :
400 : : /**
401 : : * This function releases all resources of pool.
402 : : * Caller has to make sure that all indexes and memories allocated
403 : : * from this pool not referenced anymore.
404 : : *
405 : : * @param pool
406 : : * Pointer to indexed memory pool.
407 : : * @return
408 : : * - non-zero value on error.
409 : : * - 0 on success.
410 : : */
411 : : int mlx5_ipool_destroy(struct mlx5_indexed_pool *pool);
412 : :
413 : : /**
414 : : * This function dumps debug info of pool.
415 : : *
416 : : * @param pool
417 : : * Pointer to indexed memory pool.
418 : : */
419 : : void mlx5_ipool_dump(struct mlx5_indexed_pool *pool);
420 : :
421 : : /**
422 : : * This function flushes all the cache index back to pool trunk.
423 : : *
424 : : * @param pool
425 : : * Pointer to the index memory pool handler.
426 : : *
427 : : */
428 : :
429 : : void mlx5_ipool_flush_cache(struct mlx5_indexed_pool *pool);
430 : :
431 : : /**
432 : : * This function gets the available entry from pos.
433 : : *
434 : : * @param pool
435 : : * Pointer to the index memory pool handler.
436 : : * @param pos
437 : : * Pointer to the index position start from.
438 : : *
439 : : * @return
440 : : * - Pointer to the next available entry.
441 : : *
442 : : */
443 : : void *mlx5_ipool_get_next(struct mlx5_indexed_pool *pool, uint32_t *pos);
444 : :
445 : : /**
446 : : * This function resize the ipool.
447 : : *
448 : : * @param pool
449 : : * Pointer to the index memory pool handler.
450 : : * @param num_entries
451 : : * Number of entries to be added to the pool.
452 : : * This number should be divisible by trunk_size.
453 : : *
454 : : * @return
455 : : * - non-zero value on error.
456 : : * - 0 on success.
457 : : *
458 : : */
459 : : int mlx5_ipool_resize(struct mlx5_indexed_pool *pool, uint32_t num_entries,
460 : : struct rte_flow_error *error);
461 : :
462 : : /**
463 : : * This function allocates new empty Three-level table.
464 : : *
465 : : * @param type
466 : : * The l3t can set as word, double word, quad word or pointer with index.
467 : : *
468 : : * @return
469 : : * - Pointer to the allocated l3t.
470 : : * - NULL on error. Not enough memory, or invalid arguments.
471 : : */
472 : : struct mlx5_l3t_tbl *mlx5_l3t_create(enum mlx5_l3t_type type);
473 : :
474 : : /**
475 : : * This function destroys Three-level table.
476 : : *
477 : : * @param tbl
478 : : * Pointer to the l3t.
479 : : */
480 : : void mlx5_l3t_destroy(struct mlx5_l3t_tbl *tbl);
481 : :
482 : : /**
483 : : * This function gets the index entry from Three-level table.
484 : : *
485 : : * @param tbl
486 : : * Pointer to the l3t.
487 : : * @param idx
488 : : * Index to the entry.
489 : : * @param data
490 : : * Pointer to the memory which saves the entry data.
491 : : * When function call returns 0, data contains the entry data get from
492 : : * l3t.
493 : : * When function call returns -1, data is not modified.
494 : : *
495 : : * @return
496 : : * 0 if success, -1 on error.
497 : : */
498 : :
499 : : int32_t mlx5_l3t_get_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
500 : : union mlx5_l3t_data *data);
501 : :
502 : : /**
503 : : * This function decreases and clear index entry if reference
504 : : * counter is 0 from Three-level table.
505 : : *
506 : : * @param tbl
507 : : * Pointer to the l3t.
508 : : * @param idx
509 : : * Index to the entry.
510 : : *
511 : : * @return
512 : : * The remaining reference count, 0 means entry be cleared, -1 on error.
513 : : */
514 : : int32_t mlx5_l3t_clear_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx);
515 : :
516 : : /**
517 : : * This function sets the index entry to Three-level table.
518 : : * If the entry is already set, the EEXIST errno will be given, and
519 : : * the set data will be filled to the data.
520 : : *
521 : : * @param tbl[in]
522 : : * Pointer to the l3t.
523 : : * @param idx[in]
524 : : * Index to the entry.
525 : : * @param data[in/out]
526 : : * Pointer to the memory which contains the entry data save to l3t.
527 : : * If the entry is already set, the set data will be filled.
528 : : *
529 : : * @return
530 : : * 0 if success, -1 on error.
531 : : */
532 : : int32_t mlx5_l3t_set_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
533 : : union mlx5_l3t_data *data);
534 : :
535 : : static inline void *
536 : 0 : mlx5_l3t_get_next(struct mlx5_l3t_tbl *tbl, uint32_t *pos)
537 : : {
538 : : struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
539 : : uint32_t i, j, k, g_start, m_start, e_start;
540 : 0 : uint32_t idx = *pos;
541 : : void *e_tbl;
542 : : struct mlx5_l3t_entry_word *w_e_tbl;
543 : : struct mlx5_l3t_entry_dword *dw_e_tbl;
544 : : struct mlx5_l3t_entry_qword *qw_e_tbl;
545 : : struct mlx5_l3t_entry_ptr *ptr_e_tbl;
546 : :
547 [ # # ]: 0 : if (!tbl)
548 : : return NULL;
549 : 0 : g_tbl = tbl->tbl;
550 [ # # ]: 0 : if (!g_tbl)
551 : : return NULL;
552 : 0 : g_start = (idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK;
553 : 0 : m_start = (idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK;
554 : 0 : e_start = idx & MLX5_L3T_ET_MASK;
555 [ # # ]: 0 : for (i = g_start; i < MLX5_L3T_GT_SIZE; i++) {
556 : 0 : m_tbl = g_tbl->tbl[i];
557 [ # # ]: 0 : if (!m_tbl) {
558 : : /* Jump to new table, reset the sub table start. */
559 : : m_start = 0;
560 : : e_start = 0;
561 : 0 : continue;
562 : : }
563 [ # # ]: 0 : for (j = m_start; j < MLX5_L3T_MT_SIZE; j++) {
564 [ # # ]: 0 : if (!m_tbl->tbl[j]) {
565 : : /*
566 : : * Jump to new table, reset the sub table
567 : : * start.
568 : : */
569 : : e_start = 0;
570 : 0 : continue;
571 : : }
572 : : e_tbl = m_tbl->tbl[j];
573 [ # # # # ]: 0 : switch (tbl->type) {
574 : : case MLX5_L3T_TYPE_WORD:
575 : : w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
576 [ # # ]: 0 : for (k = e_start; k < MLX5_L3T_ET_SIZE; k++) {
577 [ # # ]: 0 : if (!w_e_tbl->entry[k].data)
578 : : continue;
579 : 0 : *pos = (i << MLX5_L3T_GT_OFFSET) |
580 : 0 : (j << MLX5_L3T_MT_OFFSET) | k;
581 : 0 : return (void *)&w_e_tbl->entry[k].data;
582 : : }
583 : : break;
584 : : case MLX5_L3T_TYPE_DWORD:
585 : : dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
586 [ # # ]: 0 : for (k = e_start; k < MLX5_L3T_ET_SIZE; k++) {
587 [ # # ]: 0 : if (!dw_e_tbl->entry[k].data)
588 : : continue;
589 : 0 : *pos = (i << MLX5_L3T_GT_OFFSET) |
590 : 0 : (j << MLX5_L3T_MT_OFFSET) | k;
591 : 0 : return (void *)&dw_e_tbl->entry[k].data;
592 : : }
593 : : break;
594 : : case MLX5_L3T_TYPE_QWORD:
595 : : qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
596 [ # # ]: 0 : for (k = e_start; k < MLX5_L3T_ET_SIZE; k++) {
597 [ # # ]: 0 : if (!qw_e_tbl->entry[k].data)
598 : : continue;
599 : 0 : *pos = (i << MLX5_L3T_GT_OFFSET) |
600 : 0 : (j << MLX5_L3T_MT_OFFSET) | k;
601 : 0 : return (void *)&qw_e_tbl->entry[k].data;
602 : : }
603 : : break;
604 : : default:
605 : : ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
606 [ # # ]: 0 : for (k = e_start; k < MLX5_L3T_ET_SIZE; k++) {
607 [ # # ]: 0 : if (!ptr_e_tbl->entry[k].data)
608 : : continue;
609 : 0 : *pos = (i << MLX5_L3T_GT_OFFSET) |
610 : 0 : (j << MLX5_L3T_MT_OFFSET) | k;
611 : 0 : return ptr_e_tbl->entry[k].data;
612 : : }
613 : : break;
614 : : }
615 : : }
616 : : }
617 : : return NULL;
618 : : }
619 : :
620 : : /*
621 : : * Macros for linked list based on indexed memory.
622 : : * Example data structure:
623 : : * struct Foo {
624 : : * ILIST_ENTRY(uint16_t) next;
625 : : * ...
626 : : * }
627 : : *
628 : : */
629 : : #define ILIST_ENTRY(type) \
630 : : struct { \
631 : : type prev; /* Index of previous element. */ \
632 : : type next; /* Index of next element. */ \
633 : : }
634 : :
635 : : #define ILIST_INSERT(pool, head, idx, elem, field) \
636 : : do { \
637 : : typeof(elem) peer; \
638 : : MLX5_ASSERT((elem) && (idx)); \
639 : : (elem)->field.next = *(head); \
640 : : (elem)->field.prev = 0; \
641 : : if (*(head)) { \
642 : : (peer) = mlx5_ipool_get(pool, *(head)); \
643 : : if (peer) \
644 : : (peer)->field.prev = (idx); \
645 : : } \
646 : : *(head) = (idx); \
647 : : } while (0)
648 : :
649 : : #define ILIST_REMOVE(pool, head, idx, elem, field) \
650 : : do { \
651 : : typeof(elem) peer; \
652 : : MLX5_ASSERT(elem); \
653 : : MLX5_ASSERT(head); \
654 : : if ((elem)->field.prev) { \
655 : : (peer) = mlx5_ipool_get \
656 : : (pool, (elem)->field.prev); \
657 : : if (peer) \
658 : : (peer)->field.next = (elem)->field.next;\
659 : : } \
660 : : if ((elem)->field.next) { \
661 : : (peer) = mlx5_ipool_get \
662 : : (pool, (elem)->field.next); \
663 : : if (peer) \
664 : : (peer)->field.prev = (elem)->field.prev;\
665 : : } \
666 : : if (*(head) == (idx)) \
667 : : *(head) = (elem)->field.next; \
668 : : } while (0)
669 : :
670 : : #define ILIST_FOREACH(pool, head, idx, elem, field) \
671 : : for ((idx) = (head), (elem) = \
672 : : (idx) ? mlx5_ipool_get(pool, (idx)) : NULL; (elem); \
673 : : idx = (elem)->field.next, (elem) = \
674 : : (idx) ? mlx5_ipool_get(pool, idx) : NULL)
675 : :
676 : : /* Single index list. */
677 : : #define SILIST_ENTRY(type) \
678 : : struct { \
679 : : type next; /* Index of next element. */ \
680 : : }
681 : :
682 : : #define SILIST_INSERT(head, idx, elem, field) \
683 : : do { \
684 : : MLX5_ASSERT((elem) && (idx)); \
685 : : (elem)->field.next = *(head); \
686 : : *(head) = (idx); \
687 : : } while (0)
688 : :
689 : : #define SILIST_FOREACH(pool, head, idx, elem, field) \
690 : : for ((idx) = (head), (elem) = \
691 : : (idx) ? mlx5_ipool_get(pool, (idx)) : NULL; (elem); \
692 : : idx = (elem)->field.next, (elem) = \
693 : : (idx) ? mlx5_ipool_get(pool, idx) : NULL)
694 : :
695 : : #define MLX5_L3T_FOREACH(tbl, idx, entry) \
696 : : for (idx = 0, (entry) = mlx5_l3t_get_next((tbl), &idx); \
697 : : (entry); \
698 : : idx++, (entry) = mlx5_l3t_get_next((tbl), &idx))
699 : :
700 : : #define MLX5_IPOOL_FOREACH(ipool, idx, entry) \
701 : : for ((idx) = 0, mlx5_ipool_flush_cache((ipool)), \
702 : : (entry) = mlx5_ipool_get_next((ipool), &idx); \
703 : : (entry); idx++, (entry) = mlx5_ipool_get_next((ipool), &idx))
704 : :
705 : : #endif /* RTE_PMD_MLX5_UTILS_H_ */
|