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