/
githubmirror
/
rdma-core
Обзор
Документация
Войти
/
githubmirror
/
rdma-core
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
providers/ionic/ionic_table.h
244 строки
6 KB
Abhijit Gangurde
ionic: Add ionic provider
23 окт 2025, 07:55
23 окт 2025, 07:55
6d82ac7
Код
Авторство
О чём код?
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ /* * Copyright (c) 2018-2025 Advanced Micro Devices, Inc. All rights reserved. */ #ifndef IONIC_TABLE_H #define IONIC_TABLE_H #include <stdbool.h> #include <stdint.h> #include <stdlib.h> #include <stdio.h> /* Number of valid bits in a key */ #define TBL_KEY_SHIFT 24 /* Number bits used for index in a node */ #define TBL_NODE_SHIFT 12 #define TBL_NODE_MASK (BIT(TBL_NODE_SHIFT) - 1u) #define TBL_NODE_CAPACITY BIT(TBL_NODE_SHIFT) #define TBL_ROOT_CAPACITY BIT(TBL_KEY_SHIFT - TBL_NODE_SHIFT) struct ionic_tbl_node { void *val[TBL_NODE_CAPACITY]; }; struct ionic_tbl_root { /* for lookup in table */ struct ionic_tbl_node *node[TBL_ROOT_CAPACITY]; /* for insertion and deletion in table */ int refcount[TBL_ROOT_CAPACITY]; struct ionic_tbl_node *free_node; }; /** * ionic_tbl_init() - Initialize a table * @tbl: Table root */ static inline void ionic_tbl_init(struct ionic_tbl_root *tbl) { uint32_t node_i; tbl->free_node = NULL; for (node_i = 0; node_i < TBL_ROOT_CAPACITY; ++node_i) { tbl->node[node_i] = NULL; tbl->refcount[node_i] = 0; } } /** * ionic_tbl_init() - Destroy the table, which should be empty * @tbl: Table root */ static inline void ionic_tbl_destroy(struct ionic_tbl_root *tbl) { uint32_t node_i; /* The table should be empty. If not empty, it means the context is * being destroyed, but there are qps still in the table that have not * been destroyed. * * The interface is such that freeing the context must succeed, so here * will make a best effort to free table resources. Any qps that were * not destroyed, however will still refer to the context after it is * freed. Those qps must not be used, not even for ibv_destroy_qp, or * the application will likely crash. * * This best-effort freeing of resources replaces an assert. The * assert was seen in perftest, which will destroy the context even if * there is an error destroying a qp or other resource. */ for (node_i = 0; node_i < TBL_ROOT_CAPACITY; ++node_i) { if (!tbl->node[node_i]) continue; free(tbl->node[node_i]); } free(tbl->free_node); } /** * ionic_tbl_lookup() - Lookup value for key in the table * @tbl: Table root * @key: Key for lookup * * Synopsis: * * pthread_spin_lock(&my_table_lock); * val = ionic_tbl_lookup(&my_table, key); * if (val) * my_val_routine(val); * pthread_spin_unlock(&my_table_lock); * * Return: Value for key */ static inline void *ionic_tbl_lookup(struct ionic_tbl_root *tbl, uint32_t key) { uint32_t node_i = key >> TBL_NODE_SHIFT; if (unlikely(key >> TBL_KEY_SHIFT)) return NULL; if (unlikely(!tbl->node[node_i])) return NULL; return tbl->node[node_i]->val[key & TBL_NODE_MASK]; } /** * ionic_tbl_alloc_node() - Allocate the free node prior to insertion * @tbl: Table root * * This should be called before inserting. * * Synopsis: see ionic_tbl_insert() */ static inline void ionic_tbl_alloc_node(struct ionic_tbl_root *tbl) { if (!tbl->free_node) tbl->free_node = calloc(1, sizeof(*tbl->free_node)); } /** * ionic_tbl_free_node() - Free the free node prior to deletion * @tbl: Table root * * This should be called before deleting. * * Synopsis: see ionic_tbl_delete() */ static inline void ionic_tbl_free_node(struct ionic_tbl_root *tbl) { free(tbl->free_node); tbl->free_node = NULL; } /** * ionic_tbl_insert() - Insert a value for key in the table * @tbl: Table root * @val: Value to insert * @key: Key to insert * * The tbl->free_node must not be null when inserting. * * Synopsis: * * pthread_mutex_lock(&my_table_mut); * ionic_tbl_alloc_node(&my_table); * ionic_tbl_insert(&my_table, val, key); * pthread_mutex_unlock(&my_table_mut); * * pthread_spin_lock(&my_table_lock); * pthread_spin_unlock(&my_table_lock); */ static inline void ionic_tbl_insert(struct ionic_tbl_root *tbl, void *val, uint32_t key) { struct ionic_tbl_node *node; uint32_t node_i = key >> TBL_NODE_SHIFT; if (unlikely(key >> TBL_KEY_SHIFT)) { assert(key >> TBL_KEY_SHIFT == 0); return; } node = tbl->node[node_i]; if (!node) node = tbl->free_node; if (unlikely(!node)) { assert(node != NULL); return; } /* warning: with NDEBUG the old value will leak */ assert(node->val[key & TBL_NODE_MASK] == NULL); node->val[key & TBL_NODE_MASK] = val; if (!tbl->refcount[node_i]) { tbl->node[node_i] = node; tbl->free_node = NULL; } ++tbl->refcount[node_i]; } /** * ionic_tbl_delete() - Delete the value for key in the table * @tbl: Table root * @val: Value to insert * @key: Key to insert * * The tbl->free_node must be null when deleting. * * Synopsis: * * pthread_mutex_lock(&my_table_mut); * ionic_tbl_free_node(&my_table); * ionic_tbl_delete(&my_table, key); * pthread_mutex_unlock(&my_table_mut); * * pthread_spin_lock(&my_table_lock); * pthread_spin_unlock(&my_table_lock); * free(old_val_at_key); */ static inline void ionic_tbl_delete(struct ionic_tbl_root *tbl, uint32_t key) { struct ionic_tbl_node *node; uint32_t node_i = key >> TBL_NODE_SHIFT; if (unlikely(key >> TBL_KEY_SHIFT)) { assert(key >> TBL_KEY_SHIFT == 0); return; } node = tbl->node[node_i]; if (unlikely(!node)) { assert(node != NULL); return; } if (unlikely(!node->val[key & TBL_NODE_MASK])) { assert(node->val[key & TBL_NODE_MASK] != NULL); return; } node->val[key & TBL_NODE_MASK] = NULL; --tbl->refcount[node_i]; if (!tbl->refcount[node_i]) { /* warning: with NDEBUG the old free node will leak */ assert(node != NULL); tbl->free_node = node; tbl->node[node_i] = NULL; } } #endif /* IONIC_TABLE_H */