xref: /dpdk/drivers/net/mlx5/mlx5_utils.c (revision 46287eacc1b16600af036c8b7d5258b99ab6acbe)
1*46287eacSBing Zhao /* SPDX-License-Identifier: BSD-3-Clause
2*46287eacSBing Zhao  * Copyright 2019 Mellanox Technologies, Ltd
3*46287eacSBing Zhao  */
4*46287eacSBing Zhao 
5*46287eacSBing Zhao #include <rte_malloc.h>
6*46287eacSBing Zhao #include <rte_hash_crc.h>
7*46287eacSBing Zhao 
8*46287eacSBing Zhao #include "mlx5_utils.h"
9*46287eacSBing Zhao 
10*46287eacSBing Zhao struct mlx5_hlist *
11*46287eacSBing Zhao mlx5_hlist_create(const char *name, uint32_t size)
12*46287eacSBing Zhao {
13*46287eacSBing Zhao 	struct mlx5_hlist *h;
14*46287eacSBing Zhao 	uint32_t act_size;
15*46287eacSBing Zhao 	uint32_t alloc_size;
16*46287eacSBing Zhao 
17*46287eacSBing Zhao 	if (!size)
18*46287eacSBing Zhao 		return NULL;
19*46287eacSBing Zhao 	/* Align to the next power of 2, 32bits integer is enough now. */
20*46287eacSBing Zhao 	if (!rte_is_power_of_2(size)) {
21*46287eacSBing Zhao 		act_size = rte_align32pow2(size);
22*46287eacSBing Zhao 		DRV_LOG(WARNING, "Size 0x%" PRIX32 " is not power of 2, will "
23*46287eacSBing Zhao 			"be aligned to 0x%" PRIX32 ".\n", size, act_size);
24*46287eacSBing Zhao 	} else {
25*46287eacSBing Zhao 		act_size = size;
26*46287eacSBing Zhao 	}
27*46287eacSBing Zhao 	alloc_size = sizeof(struct mlx5_hlist) +
28*46287eacSBing Zhao 		     sizeof(struct mlx5_hlist_head) * act_size;
29*46287eacSBing Zhao 	/* Using zmalloc, then no need to initialize the heads. */
30*46287eacSBing Zhao 	h = rte_zmalloc(name, alloc_size, RTE_CACHE_LINE_SIZE);
31*46287eacSBing Zhao 	if (!h) {
32*46287eacSBing Zhao 		DRV_LOG(ERR, "No memory for hash list %s creation\n",
33*46287eacSBing Zhao 			name ? name : "None");
34*46287eacSBing Zhao 		return NULL;
35*46287eacSBing Zhao 	}
36*46287eacSBing Zhao 	if (name)
37*46287eacSBing Zhao 		snprintf(h->name, MLX5_HLIST_NAMESIZE, "%s", name);
38*46287eacSBing Zhao 	h->table_sz = act_size;
39*46287eacSBing Zhao 	h->mask = act_size - 1;
40*46287eacSBing Zhao 	DRV_LOG(DEBUG, "Hash list with %s size 0x%" PRIX32 " is created.\n",
41*46287eacSBing Zhao 		h->name, act_size);
42*46287eacSBing Zhao 	return h;
43*46287eacSBing Zhao }
44*46287eacSBing Zhao 
45*46287eacSBing Zhao struct mlx5_hlist_entry *
46*46287eacSBing Zhao mlx5_hlist_lookup(struct mlx5_hlist *h, uint64_t key)
47*46287eacSBing Zhao {
48*46287eacSBing Zhao 	uint32_t idx;
49*46287eacSBing Zhao 	struct mlx5_hlist_head *first;
50*46287eacSBing Zhao 	struct mlx5_hlist_entry *node;
51*46287eacSBing Zhao 
52*46287eacSBing Zhao 	assert(h);
53*46287eacSBing Zhao 	idx = rte_hash_crc_8byte(key, 0) & h->mask;
54*46287eacSBing Zhao 	first = &h->heads[idx];
55*46287eacSBing Zhao 	LIST_FOREACH(node, first, next) {
56*46287eacSBing Zhao 		if (node->key == key)
57*46287eacSBing Zhao 			return node;
58*46287eacSBing Zhao 	}
59*46287eacSBing Zhao 	return NULL;
60*46287eacSBing Zhao }
61*46287eacSBing Zhao 
62*46287eacSBing Zhao int
63*46287eacSBing Zhao mlx5_hlist_insert(struct mlx5_hlist *h, struct mlx5_hlist_entry *entry)
64*46287eacSBing Zhao {
65*46287eacSBing Zhao 	uint32_t idx;
66*46287eacSBing Zhao 	struct mlx5_hlist_head *first;
67*46287eacSBing Zhao 	struct mlx5_hlist_entry *node;
68*46287eacSBing Zhao 
69*46287eacSBing Zhao 	assert(h && entry);
70*46287eacSBing Zhao 	idx = rte_hash_crc_8byte(entry->key, 0) & h->mask;
71*46287eacSBing Zhao 	first = &h->heads[idx];
72*46287eacSBing Zhao 	/* No need to reuse the lookup function. */
73*46287eacSBing Zhao 	LIST_FOREACH(node, first, next) {
74*46287eacSBing Zhao 		if (node->key == entry->key)
75*46287eacSBing Zhao 			return -EEXIST;
76*46287eacSBing Zhao 	}
77*46287eacSBing Zhao 	LIST_INSERT_HEAD(first, entry, next);
78*46287eacSBing Zhao 	return 0;
79*46287eacSBing Zhao }
80*46287eacSBing Zhao 
81*46287eacSBing Zhao void
82*46287eacSBing Zhao mlx5_hlist_remove(struct mlx5_hlist *h __rte_unused,
83*46287eacSBing Zhao 		  struct mlx5_hlist_entry *entry)
84*46287eacSBing Zhao {
85*46287eacSBing Zhao 	assert(entry && entry->next.le_prev);
86*46287eacSBing Zhao 	LIST_REMOVE(entry, next);
87*46287eacSBing Zhao 	/* Set to NULL to get rid of removing action for more than once. */
88*46287eacSBing Zhao 	entry->next.le_prev = NULL;
89*46287eacSBing Zhao }
90*46287eacSBing Zhao 
91*46287eacSBing Zhao void
92*46287eacSBing Zhao mlx5_hlist_destroy(struct mlx5_hlist *h,
93*46287eacSBing Zhao 		   mlx5_hlist_destroy_callback_fn cb, void *ctx)
94*46287eacSBing Zhao {
95*46287eacSBing Zhao 	uint32_t idx;
96*46287eacSBing Zhao 	struct mlx5_hlist_entry *entry;
97*46287eacSBing Zhao 
98*46287eacSBing Zhao 	assert(h);
99*46287eacSBing Zhao 	for (idx = 0; idx < h->table_sz; ++idx) {
100*46287eacSBing Zhao 		/* no LIST_FOREACH_SAFE, using while instead */
101*46287eacSBing Zhao 		while (!LIST_EMPTY(&h->heads[idx])) {
102*46287eacSBing Zhao 			entry = LIST_FIRST(&h->heads[idx]);
103*46287eacSBing Zhao 			LIST_REMOVE(entry, next);
104*46287eacSBing Zhao 			/*
105*46287eacSBing Zhao 			 * The owner of whole element which contains data entry
106*46287eacSBing Zhao 			 * is the user, so it's the user's duty to do the clean
107*46287eacSBing Zhao 			 * up and the free work because someone may not put the
108*46287eacSBing Zhao 			 * hlist entry at the beginning(suggested to locate at
109*46287eacSBing Zhao 			 * the beginning). Or else the default free function
110*46287eacSBing Zhao 			 * will be used.
111*46287eacSBing Zhao 			 */
112*46287eacSBing Zhao 			if (cb)
113*46287eacSBing Zhao 				cb(entry, ctx);
114*46287eacSBing Zhao 			else
115*46287eacSBing Zhao 				rte_free(entry);
116*46287eacSBing Zhao 		}
117*46287eacSBing Zhao 	}
118*46287eacSBing Zhao 	rte_free(h);
119*46287eacSBing Zhao }
120