18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
48c2ecf20Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "rxe.h"
88c2ecf20Sopenharmony_ci#include "rxe_loc.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/* info about object pools
118c2ecf20Sopenharmony_ci * note that mr and mw share a single index space
128c2ecf20Sopenharmony_ci * so that one can map an lkey to the correct type of object
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_cistruct rxe_type_info rxe_type_info[RXE_NUM_TYPES] = {
158c2ecf20Sopenharmony_ci	[RXE_TYPE_UC] = {
168c2ecf20Sopenharmony_ci		.name		= "rxe-uc",
178c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_ucontext),
188c2ecf20Sopenharmony_ci		.flags          = RXE_POOL_NO_ALLOC,
198c2ecf20Sopenharmony_ci	},
208c2ecf20Sopenharmony_ci	[RXE_TYPE_PD] = {
218c2ecf20Sopenharmony_ci		.name		= "rxe-pd",
228c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_pd),
238c2ecf20Sopenharmony_ci		.flags		= RXE_POOL_NO_ALLOC,
248c2ecf20Sopenharmony_ci	},
258c2ecf20Sopenharmony_ci	[RXE_TYPE_AH] = {
268c2ecf20Sopenharmony_ci		.name		= "rxe-ah",
278c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_ah),
288c2ecf20Sopenharmony_ci		.flags		= RXE_POOL_ATOMIC | RXE_POOL_NO_ALLOC,
298c2ecf20Sopenharmony_ci	},
308c2ecf20Sopenharmony_ci	[RXE_TYPE_SRQ] = {
318c2ecf20Sopenharmony_ci		.name		= "rxe-srq",
328c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_srq),
338c2ecf20Sopenharmony_ci		.flags		= RXE_POOL_INDEX | RXE_POOL_NO_ALLOC,
348c2ecf20Sopenharmony_ci		.min_index	= RXE_MIN_SRQ_INDEX,
358c2ecf20Sopenharmony_ci		.max_index	= RXE_MAX_SRQ_INDEX,
368c2ecf20Sopenharmony_ci	},
378c2ecf20Sopenharmony_ci	[RXE_TYPE_QP] = {
388c2ecf20Sopenharmony_ci		.name		= "rxe-qp",
398c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_qp),
408c2ecf20Sopenharmony_ci		.cleanup	= rxe_qp_cleanup,
418c2ecf20Sopenharmony_ci		.flags		= RXE_POOL_INDEX,
428c2ecf20Sopenharmony_ci		.min_index	= RXE_MIN_QP_INDEX,
438c2ecf20Sopenharmony_ci		.max_index	= RXE_MAX_QP_INDEX,
448c2ecf20Sopenharmony_ci	},
458c2ecf20Sopenharmony_ci	[RXE_TYPE_CQ] = {
468c2ecf20Sopenharmony_ci		.name		= "rxe-cq",
478c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_cq),
488c2ecf20Sopenharmony_ci		.flags          = RXE_POOL_NO_ALLOC,
498c2ecf20Sopenharmony_ci		.cleanup	= rxe_cq_cleanup,
508c2ecf20Sopenharmony_ci	},
518c2ecf20Sopenharmony_ci	[RXE_TYPE_MR] = {
528c2ecf20Sopenharmony_ci		.name		= "rxe-mr",
538c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_mem),
548c2ecf20Sopenharmony_ci		.cleanup	= rxe_mem_cleanup,
558c2ecf20Sopenharmony_ci		.flags		= RXE_POOL_INDEX,
568c2ecf20Sopenharmony_ci		.max_index	= RXE_MAX_MR_INDEX,
578c2ecf20Sopenharmony_ci		.min_index	= RXE_MIN_MR_INDEX,
588c2ecf20Sopenharmony_ci	},
598c2ecf20Sopenharmony_ci	[RXE_TYPE_MW] = {
608c2ecf20Sopenharmony_ci		.name		= "rxe-mw",
618c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_mem),
628c2ecf20Sopenharmony_ci		.flags		= RXE_POOL_INDEX,
638c2ecf20Sopenharmony_ci		.max_index	= RXE_MAX_MW_INDEX,
648c2ecf20Sopenharmony_ci		.min_index	= RXE_MIN_MW_INDEX,
658c2ecf20Sopenharmony_ci	},
668c2ecf20Sopenharmony_ci	[RXE_TYPE_MC_GRP] = {
678c2ecf20Sopenharmony_ci		.name		= "rxe-mc_grp",
688c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_mc_grp),
698c2ecf20Sopenharmony_ci		.cleanup	= rxe_mc_cleanup,
708c2ecf20Sopenharmony_ci		.flags		= RXE_POOL_KEY,
718c2ecf20Sopenharmony_ci		.key_offset	= offsetof(struct rxe_mc_grp, mgid),
728c2ecf20Sopenharmony_ci		.key_size	= sizeof(union ib_gid),
738c2ecf20Sopenharmony_ci	},
748c2ecf20Sopenharmony_ci	[RXE_TYPE_MC_ELEM] = {
758c2ecf20Sopenharmony_ci		.name		= "rxe-mc_elem",
768c2ecf20Sopenharmony_ci		.size		= sizeof(struct rxe_mc_elem),
778c2ecf20Sopenharmony_ci		.flags		= RXE_POOL_ATOMIC,
788c2ecf20Sopenharmony_ci	},
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic inline const char *pool_name(struct rxe_pool *pool)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	return rxe_type_info[pool->type].name;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int rxe_pool_init_index(struct rxe_pool *pool, u32 max, u32 min)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	int err = 0;
898c2ecf20Sopenharmony_ci	size_t size;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if ((max - min + 1) < pool->max_elem) {
928c2ecf20Sopenharmony_ci		pr_warn("not enough indices for max_elem\n");
938c2ecf20Sopenharmony_ci		err = -EINVAL;
948c2ecf20Sopenharmony_ci		goto out;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	pool->max_index = max;
988c2ecf20Sopenharmony_ci	pool->min_index = min;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	size = BITS_TO_LONGS(max - min + 1) * sizeof(long);
1018c2ecf20Sopenharmony_ci	pool->table = kmalloc(size, GFP_KERNEL);
1028c2ecf20Sopenharmony_ci	if (!pool->table) {
1038c2ecf20Sopenharmony_ci		err = -ENOMEM;
1048c2ecf20Sopenharmony_ci		goto out;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	pool->table_size = size;
1088c2ecf20Sopenharmony_ci	bitmap_zero(pool->table, max - min + 1);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ciout:
1118c2ecf20Sopenharmony_ci	return err;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ciint rxe_pool_init(
1158c2ecf20Sopenharmony_ci	struct rxe_dev		*rxe,
1168c2ecf20Sopenharmony_ci	struct rxe_pool		*pool,
1178c2ecf20Sopenharmony_ci	enum rxe_elem_type	type,
1188c2ecf20Sopenharmony_ci	unsigned int		max_elem)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	int			err = 0;
1218c2ecf20Sopenharmony_ci	size_t			size = rxe_type_info[type].size;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	memset(pool, 0, sizeof(*pool));
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	pool->rxe		= rxe;
1268c2ecf20Sopenharmony_ci	pool->type		= type;
1278c2ecf20Sopenharmony_ci	pool->max_elem		= max_elem;
1288c2ecf20Sopenharmony_ci	pool->elem_size		= ALIGN(size, RXE_POOL_ALIGN);
1298c2ecf20Sopenharmony_ci	pool->flags		= rxe_type_info[type].flags;
1308c2ecf20Sopenharmony_ci	pool->tree		= RB_ROOT;
1318c2ecf20Sopenharmony_ci	pool->cleanup		= rxe_type_info[type].cleanup;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	atomic_set(&pool->num_elem, 0);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	kref_init(&pool->ref_cnt);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	rwlock_init(&pool->pool_lock);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (rxe_type_info[type].flags & RXE_POOL_INDEX) {
1408c2ecf20Sopenharmony_ci		err = rxe_pool_init_index(pool,
1418c2ecf20Sopenharmony_ci					  rxe_type_info[type].max_index,
1428c2ecf20Sopenharmony_ci					  rxe_type_info[type].min_index);
1438c2ecf20Sopenharmony_ci		if (err)
1448c2ecf20Sopenharmony_ci			goto out;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (rxe_type_info[type].flags & RXE_POOL_KEY) {
1488c2ecf20Sopenharmony_ci		pool->key_offset = rxe_type_info[type].key_offset;
1498c2ecf20Sopenharmony_ci		pool->key_size = rxe_type_info[type].key_size;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	pool->state = RXE_POOL_STATE_VALID;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ciout:
1558c2ecf20Sopenharmony_ci	return err;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic void rxe_pool_release(struct kref *kref)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	struct rxe_pool *pool = container_of(kref, struct rxe_pool, ref_cnt);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	pool->state = RXE_POOL_STATE_INVALID;
1638c2ecf20Sopenharmony_ci	kfree(pool->table);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic void rxe_pool_put(struct rxe_pool *pool)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	kref_put(&pool->ref_cnt, rxe_pool_release);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_civoid rxe_pool_cleanup(struct rxe_pool *pool)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	unsigned long flags;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	write_lock_irqsave(&pool->pool_lock, flags);
1768c2ecf20Sopenharmony_ci	pool->state = RXE_POOL_STATE_INVALID;
1778c2ecf20Sopenharmony_ci	if (atomic_read(&pool->num_elem) > 0)
1788c2ecf20Sopenharmony_ci		pr_warn("%s pool destroyed with unfree'd elem\n",
1798c2ecf20Sopenharmony_ci			pool_name(pool));
1808c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&pool->pool_lock, flags);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	rxe_pool_put(pool);
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic u32 alloc_index(struct rxe_pool *pool)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	u32 index;
1888c2ecf20Sopenharmony_ci	u32 range = pool->max_index - pool->min_index + 1;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	index = find_next_zero_bit(pool->table, range, pool->last);
1918c2ecf20Sopenharmony_ci	if (index >= range)
1928c2ecf20Sopenharmony_ci		index = find_first_zero_bit(pool->table, range);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	WARN_ON_ONCE(index >= range);
1958c2ecf20Sopenharmony_ci	set_bit(index, pool->table);
1968c2ecf20Sopenharmony_ci	pool->last = index;
1978c2ecf20Sopenharmony_ci	return index + pool->min_index;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic void insert_index(struct rxe_pool *pool, struct rxe_pool_entry *new)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct rb_node **link = &pool->tree.rb_node;
2038c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
2048c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	while (*link) {
2078c2ecf20Sopenharmony_ci		parent = *link;
2088c2ecf20Sopenharmony_ci		elem = rb_entry(parent, struct rxe_pool_entry, node);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		if (elem->index == new->index) {
2118c2ecf20Sopenharmony_ci			pr_warn("element already exists!\n");
2128c2ecf20Sopenharmony_ci			goto out;
2138c2ecf20Sopenharmony_ci		}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		if (elem->index > new->index)
2168c2ecf20Sopenharmony_ci			link = &(*link)->rb_left;
2178c2ecf20Sopenharmony_ci		else
2188c2ecf20Sopenharmony_ci			link = &(*link)->rb_right;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	rb_link_node(&new->node, parent, link);
2228c2ecf20Sopenharmony_ci	rb_insert_color(&new->node, &pool->tree);
2238c2ecf20Sopenharmony_ciout:
2248c2ecf20Sopenharmony_ci	return;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic void insert_key(struct rxe_pool *pool, struct rxe_pool_entry *new)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct rb_node **link = &pool->tree.rb_node;
2308c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
2318c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem;
2328c2ecf20Sopenharmony_ci	int cmp;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	while (*link) {
2358c2ecf20Sopenharmony_ci		parent = *link;
2368c2ecf20Sopenharmony_ci		elem = rb_entry(parent, struct rxe_pool_entry, node);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci		cmp = memcmp((u8 *)elem + pool->key_offset,
2398c2ecf20Sopenharmony_ci			     (u8 *)new + pool->key_offset, pool->key_size);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		if (cmp == 0) {
2428c2ecf20Sopenharmony_ci			pr_warn("key already exists!\n");
2438c2ecf20Sopenharmony_ci			goto out;
2448c2ecf20Sopenharmony_ci		}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci		if (cmp > 0)
2478c2ecf20Sopenharmony_ci			link = &(*link)->rb_left;
2488c2ecf20Sopenharmony_ci		else
2498c2ecf20Sopenharmony_ci			link = &(*link)->rb_right;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	rb_link_node(&new->node, parent, link);
2538c2ecf20Sopenharmony_ci	rb_insert_color(&new->node, &pool->tree);
2548c2ecf20Sopenharmony_ciout:
2558c2ecf20Sopenharmony_ci	return;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_civoid rxe_add_key(void *arg, void *key)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem = arg;
2618c2ecf20Sopenharmony_ci	struct rxe_pool *pool = elem->pool;
2628c2ecf20Sopenharmony_ci	unsigned long flags;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	write_lock_irqsave(&pool->pool_lock, flags);
2658c2ecf20Sopenharmony_ci	memcpy((u8 *)elem + pool->key_offset, key, pool->key_size);
2668c2ecf20Sopenharmony_ci	insert_key(pool, elem);
2678c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&pool->pool_lock, flags);
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_civoid rxe_drop_key(void *arg)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem = arg;
2738c2ecf20Sopenharmony_ci	struct rxe_pool *pool = elem->pool;
2748c2ecf20Sopenharmony_ci	unsigned long flags;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	write_lock_irqsave(&pool->pool_lock, flags);
2778c2ecf20Sopenharmony_ci	rb_erase(&elem->node, &pool->tree);
2788c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&pool->pool_lock, flags);
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_civoid rxe_add_index(void *arg)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem = arg;
2848c2ecf20Sopenharmony_ci	struct rxe_pool *pool = elem->pool;
2858c2ecf20Sopenharmony_ci	unsigned long flags;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	write_lock_irqsave(&pool->pool_lock, flags);
2888c2ecf20Sopenharmony_ci	elem->index = alloc_index(pool);
2898c2ecf20Sopenharmony_ci	insert_index(pool, elem);
2908c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&pool->pool_lock, flags);
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_civoid rxe_drop_index(void *arg)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem = arg;
2968c2ecf20Sopenharmony_ci	struct rxe_pool *pool = elem->pool;
2978c2ecf20Sopenharmony_ci	unsigned long flags;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	write_lock_irqsave(&pool->pool_lock, flags);
3008c2ecf20Sopenharmony_ci	clear_bit(elem->index - pool->min_index, pool->table);
3018c2ecf20Sopenharmony_ci	rb_erase(&elem->node, &pool->tree);
3028c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&pool->pool_lock, flags);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_civoid *rxe_alloc(struct rxe_pool *pool)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem;
3088c2ecf20Sopenharmony_ci	unsigned long flags;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	might_sleep_if(!(pool->flags & RXE_POOL_ATOMIC));
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	read_lock_irqsave(&pool->pool_lock, flags);
3138c2ecf20Sopenharmony_ci	if (pool->state != RXE_POOL_STATE_VALID) {
3148c2ecf20Sopenharmony_ci		read_unlock_irqrestore(&pool->pool_lock, flags);
3158c2ecf20Sopenharmony_ci		return NULL;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci	kref_get(&pool->ref_cnt);
3188c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&pool->pool_lock, flags);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (!ib_device_try_get(&pool->rxe->ib_dev))
3218c2ecf20Sopenharmony_ci		goto out_put_pool;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (atomic_inc_return(&pool->num_elem) > pool->max_elem)
3248c2ecf20Sopenharmony_ci		goto out_cnt;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	elem = kzalloc(rxe_type_info[pool->type].size,
3278c2ecf20Sopenharmony_ci				 (pool->flags & RXE_POOL_ATOMIC) ?
3288c2ecf20Sopenharmony_ci				 GFP_ATOMIC : GFP_KERNEL);
3298c2ecf20Sopenharmony_ci	if (!elem)
3308c2ecf20Sopenharmony_ci		goto out_cnt;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	elem->pool = pool;
3338c2ecf20Sopenharmony_ci	kref_init(&elem->ref_cnt);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	return elem;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ciout_cnt:
3388c2ecf20Sopenharmony_ci	atomic_dec(&pool->num_elem);
3398c2ecf20Sopenharmony_ci	ib_device_put(&pool->rxe->ib_dev);
3408c2ecf20Sopenharmony_ciout_put_pool:
3418c2ecf20Sopenharmony_ci	rxe_pool_put(pool);
3428c2ecf20Sopenharmony_ci	return NULL;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ciint rxe_add_to_pool(struct rxe_pool *pool, struct rxe_pool_entry *elem)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	unsigned long flags;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	might_sleep_if(!(pool->flags & RXE_POOL_ATOMIC));
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	read_lock_irqsave(&pool->pool_lock, flags);
3528c2ecf20Sopenharmony_ci	if (pool->state != RXE_POOL_STATE_VALID) {
3538c2ecf20Sopenharmony_ci		read_unlock_irqrestore(&pool->pool_lock, flags);
3548c2ecf20Sopenharmony_ci		return -EINVAL;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci	kref_get(&pool->ref_cnt);
3578c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&pool->pool_lock, flags);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (!ib_device_try_get(&pool->rxe->ib_dev))
3608c2ecf20Sopenharmony_ci		goto out_put_pool;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (atomic_inc_return(&pool->num_elem) > pool->max_elem)
3638c2ecf20Sopenharmony_ci		goto out_cnt;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	elem->pool = pool;
3668c2ecf20Sopenharmony_ci	kref_init(&elem->ref_cnt);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	return 0;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ciout_cnt:
3718c2ecf20Sopenharmony_ci	atomic_dec(&pool->num_elem);
3728c2ecf20Sopenharmony_ci	ib_device_put(&pool->rxe->ib_dev);
3738c2ecf20Sopenharmony_ciout_put_pool:
3748c2ecf20Sopenharmony_ci	rxe_pool_put(pool);
3758c2ecf20Sopenharmony_ci	return -EINVAL;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_civoid rxe_elem_release(struct kref *kref)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem =
3818c2ecf20Sopenharmony_ci		container_of(kref, struct rxe_pool_entry, ref_cnt);
3828c2ecf20Sopenharmony_ci	struct rxe_pool *pool = elem->pool;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (pool->cleanup)
3858c2ecf20Sopenharmony_ci		pool->cleanup(elem);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if (!(pool->flags & RXE_POOL_NO_ALLOC))
3888c2ecf20Sopenharmony_ci		kfree(elem);
3898c2ecf20Sopenharmony_ci	atomic_dec(&pool->num_elem);
3908c2ecf20Sopenharmony_ci	ib_device_put(&pool->rxe->ib_dev);
3918c2ecf20Sopenharmony_ci	rxe_pool_put(pool);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_civoid *rxe_pool_get_index(struct rxe_pool *pool, u32 index)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct rb_node *node = NULL;
3978c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem = NULL;
3988c2ecf20Sopenharmony_ci	unsigned long flags;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	read_lock_irqsave(&pool->pool_lock, flags);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (pool->state != RXE_POOL_STATE_VALID)
4038c2ecf20Sopenharmony_ci		goto out;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	node = pool->tree.rb_node;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	while (node) {
4088c2ecf20Sopenharmony_ci		elem = rb_entry(node, struct rxe_pool_entry, node);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci		if (elem->index > index)
4118c2ecf20Sopenharmony_ci			node = node->rb_left;
4128c2ecf20Sopenharmony_ci		else if (elem->index < index)
4138c2ecf20Sopenharmony_ci			node = node->rb_right;
4148c2ecf20Sopenharmony_ci		else {
4158c2ecf20Sopenharmony_ci			kref_get(&elem->ref_cnt);
4168c2ecf20Sopenharmony_ci			break;
4178c2ecf20Sopenharmony_ci		}
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ciout:
4218c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&pool->pool_lock, flags);
4228c2ecf20Sopenharmony_ci	return node ? elem : NULL;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_civoid *rxe_pool_get_key(struct rxe_pool *pool, void *key)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct rb_node *node = NULL;
4288c2ecf20Sopenharmony_ci	struct rxe_pool_entry *elem = NULL;
4298c2ecf20Sopenharmony_ci	int cmp;
4308c2ecf20Sopenharmony_ci	unsigned long flags;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	read_lock_irqsave(&pool->pool_lock, flags);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (pool->state != RXE_POOL_STATE_VALID)
4358c2ecf20Sopenharmony_ci		goto out;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	node = pool->tree.rb_node;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	while (node) {
4408c2ecf20Sopenharmony_ci		elem = rb_entry(node, struct rxe_pool_entry, node);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci		cmp = memcmp((u8 *)elem + pool->key_offset,
4438c2ecf20Sopenharmony_ci			     key, pool->key_size);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		if (cmp > 0)
4468c2ecf20Sopenharmony_ci			node = node->rb_left;
4478c2ecf20Sopenharmony_ci		else if (cmp < 0)
4488c2ecf20Sopenharmony_ci			node = node->rb_right;
4498c2ecf20Sopenharmony_ci		else
4508c2ecf20Sopenharmony_ci			break;
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (node)
4548c2ecf20Sopenharmony_ci		kref_get(&elem->ref_cnt);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ciout:
4578c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&pool->pool_lock, flags);
4588c2ecf20Sopenharmony_ci	return node ? elem : NULL;
4598c2ecf20Sopenharmony_ci}
460