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 } 120