163fa15dbSBob Pearson // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
28700e3e7SMoni Shoua /*
38700e3e7SMoni Shoua  * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
48700e3e7SMoni Shoua  * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
58700e3e7SMoni Shoua  */
68700e3e7SMoni Shoua 
78700e3e7SMoni Shoua #include "rxe.h"
88700e3e7SMoni Shoua 
9215d0a75SBob Pearson #define RXE_POOL_TIMEOUT	(200)
1088f9335fSBob Pearson #define RXE_POOL_ALIGN		(16)
1188f9335fSBob Pearson 
12000b8490SJoe Perches static const struct rxe_type_info {
13000b8490SJoe Perches 	const char *name;
14000b8490SJoe Perches 	size_t size;
15000b8490SJoe Perches 	size_t elem_offset;
16b4a47f68SBob Pearson 	void (*cleanup)(struct rxe_pool_elem *elem);
17000b8490SJoe Perches 	u32 min_index;
18000b8490SJoe Perches 	u32 max_index;
193ccffe8aSBob Pearson 	u32 max_elem;
20000b8490SJoe Perches } rxe_type_info[RXE_NUM_TYPES] = {
218700e3e7SMoni Shoua 	[RXE_TYPE_UC] = {
22df34dc9eSBob Pearson 		.name		= "uc",
238700e3e7SMoni Shoua 		.size		= sizeof(struct rxe_ucontext),
2402827b67SBob Pearson 		.elem_offset	= offsetof(struct rxe_ucontext, elem),
253225717fSBob Pearson 		.min_index	= 1,
263225717fSBob Pearson 		.max_index	= RXE_MAX_UCONTEXT,
273ccffe8aSBob Pearson 		.max_elem	= RXE_MAX_UCONTEXT,
288700e3e7SMoni Shoua 	},
298700e3e7SMoni Shoua 	[RXE_TYPE_PD] = {
30df34dc9eSBob Pearson 		.name		= "pd",
318700e3e7SMoni Shoua 		.size		= sizeof(struct rxe_pd),
3202827b67SBob Pearson 		.elem_offset	= offsetof(struct rxe_pd, elem),
333225717fSBob Pearson 		.min_index	= 1,
343225717fSBob Pearson 		.max_index	= RXE_MAX_PD,
353ccffe8aSBob Pearson 		.max_elem	= RXE_MAX_PD,
368700e3e7SMoni Shoua 	},
378700e3e7SMoni Shoua 	[RXE_TYPE_AH] = {
38df34dc9eSBob Pearson 		.name		= "ah",
398700e3e7SMoni Shoua 		.size		= sizeof(struct rxe_ah),
4002827b67SBob Pearson 		.elem_offset	= offsetof(struct rxe_ah, elem),
4199c13a3eSBob Pearson 		.min_index	= RXE_MIN_AH_INDEX,
4299c13a3eSBob Pearson 		.max_index	= RXE_MAX_AH_INDEX,
433ccffe8aSBob Pearson 		.max_elem	= RXE_MAX_AH,
448700e3e7SMoni Shoua 	},
458700e3e7SMoni Shoua 	[RXE_TYPE_SRQ] = {
46df34dc9eSBob Pearson 		.name		= "srq",
478700e3e7SMoni Shoua 		.size		= sizeof(struct rxe_srq),
4802827b67SBob Pearson 		.elem_offset	= offsetof(struct rxe_srq, elem),
49b2a41678SBob Pearson 		.cleanup	= rxe_srq_cleanup,
508700e3e7SMoni Shoua 		.min_index	= RXE_MIN_SRQ_INDEX,
518700e3e7SMoni Shoua 		.max_index	= RXE_MAX_SRQ_INDEX,
523ccffe8aSBob Pearson 		.max_elem	= RXE_MAX_SRQ,
538700e3e7SMoni Shoua 	},
548700e3e7SMoni Shoua 	[RXE_TYPE_QP] = {
55df34dc9eSBob Pearson 		.name		= "qp",
568700e3e7SMoni Shoua 		.size		= sizeof(struct rxe_qp),
5702827b67SBob Pearson 		.elem_offset	= offsetof(struct rxe_qp, elem),
588700e3e7SMoni Shoua 		.cleanup	= rxe_qp_cleanup,
598700e3e7SMoni Shoua 		.min_index	= RXE_MIN_QP_INDEX,
608700e3e7SMoni Shoua 		.max_index	= RXE_MAX_QP_INDEX,
613ccffe8aSBob Pearson 		.max_elem	= RXE_MAX_QP,
628700e3e7SMoni Shoua 	},
638700e3e7SMoni Shoua 	[RXE_TYPE_CQ] = {
64df34dc9eSBob Pearson 		.name		= "cq",
658700e3e7SMoni Shoua 		.size		= sizeof(struct rxe_cq),
6602827b67SBob Pearson 		.elem_offset	= offsetof(struct rxe_cq, elem),
678700e3e7SMoni Shoua 		.cleanup	= rxe_cq_cleanup,
683225717fSBob Pearson 		.min_index	= 1,
693225717fSBob Pearson 		.max_index	= RXE_MAX_CQ,
703ccffe8aSBob Pearson 		.max_elem	= RXE_MAX_CQ,
718700e3e7SMoni Shoua 	},
728700e3e7SMoni Shoua 	[RXE_TYPE_MR] = {
73df34dc9eSBob Pearson 		.name		= "mr",
74364e282cSBob Pearson 		.size		= sizeof(struct rxe_mr),
7502827b67SBob Pearson 		.elem_offset	= offsetof(struct rxe_mr, elem),
76364e282cSBob Pearson 		.cleanup	= rxe_mr_cleanup,
778700e3e7SMoni Shoua 		.min_index	= RXE_MIN_MR_INDEX,
78000b8490SJoe Perches 		.max_index	= RXE_MAX_MR_INDEX,
793ccffe8aSBob Pearson 		.max_elem	= RXE_MAX_MR,
808700e3e7SMoni Shoua 	},
818700e3e7SMoni Shoua 	[RXE_TYPE_MW] = {
82df34dc9eSBob Pearson 		.name		= "mw",
83364e282cSBob Pearson 		.size		= sizeof(struct rxe_mw),
8402827b67SBob Pearson 		.elem_offset	= offsetof(struct rxe_mw, elem),
85cde3f5d6SBob Pearson 		.cleanup	= rxe_mw_cleanup,
868700e3e7SMoni Shoua 		.min_index	= RXE_MIN_MW_INDEX,
87000b8490SJoe Perches 		.max_index	= RXE_MAX_MW_INDEX,
883ccffe8aSBob Pearson 		.max_elem	= RXE_MAX_MW,
898700e3e7SMoni Shoua 	},
908700e3e7SMoni Shoua };
918700e3e7SMoni Shoua 
rxe_pool_init(struct rxe_dev * rxe,struct rxe_pool * pool,enum rxe_elem_type type)923225717fSBob Pearson void rxe_pool_init(struct rxe_dev *rxe, struct rxe_pool *pool,
933ccffe8aSBob Pearson 		   enum rxe_elem_type type)
948700e3e7SMoni Shoua {
95c95acedbSBob Pearson 	const struct rxe_type_info *info = &rxe_type_info[type];
968700e3e7SMoni Shoua 
978700e3e7SMoni Shoua 	memset(pool, 0, sizeof(*pool));
988700e3e7SMoni Shoua 
998700e3e7SMoni Shoua 	pool->rxe		= rxe;
100c95acedbSBob Pearson 	pool->name		= info->name;
1018700e3e7SMoni Shoua 	pool->type		= type;
1023ccffe8aSBob Pearson 	pool->max_elem		= info->max_elem;
103c95acedbSBob Pearson 	pool->elem_size		= ALIGN(info->size, RXE_POOL_ALIGN);
104c95acedbSBob Pearson 	pool->elem_offset	= info->elem_offset;
105c95acedbSBob Pearson 	pool->cleanup		= info->cleanup;
1068700e3e7SMoni Shoua 
1078700e3e7SMoni Shoua 	atomic_set(&pool->num_elem, 0);
1088700e3e7SMoni Shoua 
1093225717fSBob Pearson 	xa_init_flags(&pool->xa, XA_FLAGS_ALLOC);
1103225717fSBob Pearson 	pool->limit.min = info->min_index;
1113225717fSBob Pearson 	pool->limit.max = info->max_index;
1128700e3e7SMoni Shoua }
1138700e3e7SMoni Shoua 
rxe_pool_cleanup(struct rxe_pool * pool)1141ceb25c8SYuval Shaia void rxe_pool_cleanup(struct rxe_pool *pool)
1158700e3e7SMoni Shoua {
1163225717fSBob Pearson 	WARN_ON(!xa_empty(&pool->xa));
1178700e3e7SMoni Shoua }
1188700e3e7SMoni Shoua 
__rxe_add_to_pool(struct rxe_pool * pool,struct rxe_pool_elem * elem,bool sleepable)119215d0a75SBob Pearson int __rxe_add_to_pool(struct rxe_pool *pool, struct rxe_pool_elem *elem,
120215d0a75SBob Pearson 				bool sleepable)
12121a428a0SLeon Romanovsky {
1223225717fSBob Pearson 	int err;
123215d0a75SBob Pearson 	gfp_t gfp_flags;
1243225717fSBob Pearson 
12521a428a0SLeon Romanovsky 	if (atomic_inc_return(&pool->num_elem) > pool->max_elem)
1263225717fSBob Pearson 		goto err_cnt;
12721a428a0SLeon Romanovsky 
12821a428a0SLeon Romanovsky 	elem->pool = pool;
129b92d766cSBob Pearson 	elem->obj = (u8 *)elem - pool->elem_offset;
13021a428a0SLeon Romanovsky 	kref_init(&elem->ref_cnt);
131215d0a75SBob Pearson 	init_completion(&elem->complete);
13221a428a0SLeon Romanovsky 
133215d0a75SBob Pearson 	/* AH objects are unique in that the create_ah verb
134215d0a75SBob Pearson 	 * can be called in atomic context. If the create_ah
135215d0a75SBob Pearson 	 * call is not sleepable use GFP_ATOMIC.
136215d0a75SBob Pearson 	 */
137215d0a75SBob Pearson 	gfp_flags = sleepable ? GFP_KERNEL : GFP_ATOMIC;
138215d0a75SBob Pearson 
139215d0a75SBob Pearson 	if (sleepable)
140215d0a75SBob Pearson 		might_sleep();
141215d0a75SBob Pearson 	err = xa_alloc_cyclic(&pool->xa, &elem->index, NULL, pool->limit,
142215d0a75SBob Pearson 			      &pool->next, gfp_flags);
1431a685940SDongliang Mu 	if (err < 0)
1443225717fSBob Pearson 		goto err_cnt;
1453225717fSBob Pearson 
14621a428a0SLeon Romanovsky 	return 0;
14721a428a0SLeon Romanovsky 
1483225717fSBob Pearson err_cnt:
14921a428a0SLeon Romanovsky 	atomic_dec(&pool->num_elem);
15021a428a0SLeon Romanovsky 	return -EINVAL;
15121a428a0SLeon Romanovsky }
15221a428a0SLeon Romanovsky 
rxe_pool_get_index(struct rxe_pool * pool,u32 index)1533c3e4d58SBob Pearson void *rxe_pool_get_index(struct rxe_pool *pool, u32 index)
1548700e3e7SMoni Shoua {
15502827b67SBob Pearson 	struct rxe_pool_elem *elem;
1563225717fSBob Pearson 	struct xarray *xa = &pool->xa;
157b92d766cSBob Pearson 	void *obj;
1588700e3e7SMoni Shoua 
159*b54c2a25SBob Pearson 	rcu_read_lock();
1603225717fSBob Pearson 	elem = xa_load(xa, index);
1613225717fSBob Pearson 	if (elem && kref_get_unless_zero(&elem->ref_cnt))
162b92d766cSBob Pearson 		obj = elem->obj;
1633225717fSBob Pearson 	else
1642622aa71SBob Pearson 		obj = NULL;
165*b54c2a25SBob Pearson 	rcu_read_unlock();
166eae5f064SBob Pearson 
1672622aa71SBob Pearson 	return obj;
1688700e3e7SMoni Shoua }
1693225717fSBob Pearson 
rxe_elem_release(struct kref * kref)1703225717fSBob Pearson static void rxe_elem_release(struct kref *kref)
1713225717fSBob Pearson {
1723225717fSBob Pearson 	struct rxe_pool_elem *elem = container_of(kref, typeof(*elem), ref_cnt);
1733225717fSBob Pearson 
174215d0a75SBob Pearson 	complete(&elem->complete);
175215d0a75SBob Pearson }
176215d0a75SBob Pearson 
__rxe_cleanup(struct rxe_pool_elem * elem,bool sleepable)177215d0a75SBob Pearson int __rxe_cleanup(struct rxe_pool_elem *elem, bool sleepable)
178215d0a75SBob Pearson {
179215d0a75SBob Pearson 	struct rxe_pool *pool = elem->pool;
180215d0a75SBob Pearson 	struct xarray *xa = &pool->xa;
181215d0a75SBob Pearson 	static int timeout = RXE_POOL_TIMEOUT;
182215d0a75SBob Pearson 	int ret, err = 0;
183215d0a75SBob Pearson 	void *xa_ret;
184215d0a75SBob Pearson 
185215d0a75SBob Pearson 	if (sleepable)
186215d0a75SBob Pearson 		might_sleep();
187215d0a75SBob Pearson 
188215d0a75SBob Pearson 	/* erase xarray entry to prevent looking up
189215d0a75SBob Pearson 	 * the pool elem from its index
190215d0a75SBob Pearson 	 */
191*b54c2a25SBob Pearson 	xa_ret = xa_erase(xa, elem->index);
192215d0a75SBob Pearson 	WARN_ON(xa_err(xa_ret));
193215d0a75SBob Pearson 
194215d0a75SBob Pearson 	/* if this is the last call to rxe_put complete the
195215d0a75SBob Pearson 	 * object. It is safe to touch obj->elem after this since
196215d0a75SBob Pearson 	 * it is freed below
197215d0a75SBob Pearson 	 */
198215d0a75SBob Pearson 	__rxe_put(elem);
199215d0a75SBob Pearson 
200215d0a75SBob Pearson 	/* wait until all references to the object have been
201215d0a75SBob Pearson 	 * dropped before final object specific cleanup and
202215d0a75SBob Pearson 	 * return to rdma-core
203215d0a75SBob Pearson 	 */
204215d0a75SBob Pearson 	if (sleepable) {
205215d0a75SBob Pearson 		if (!completion_done(&elem->complete) && timeout) {
206215d0a75SBob Pearson 			ret = wait_for_completion_timeout(&elem->complete,
207215d0a75SBob Pearson 					timeout);
208215d0a75SBob Pearson 
209215d0a75SBob Pearson 			/* Shouldn't happen. There are still references to
210215d0a75SBob Pearson 			 * the object but, rather than deadlock, free the
211215d0a75SBob Pearson 			 * object or pass back to rdma-core.
212215d0a75SBob Pearson 			 */
213215d0a75SBob Pearson 			if (WARN_ON(!ret))
214215d0a75SBob Pearson 				err = -EINVAL;
215215d0a75SBob Pearson 		}
216215d0a75SBob Pearson 	} else {
217215d0a75SBob Pearson 		unsigned long until = jiffies + timeout;
218215d0a75SBob Pearson 
219215d0a75SBob Pearson 		/* AH objects are unique in that the destroy_ah verb
220215d0a75SBob Pearson 		 * can be called in atomic context. This delay
221215d0a75SBob Pearson 		 * replaces the wait_for_completion call above
222215d0a75SBob Pearson 		 * when the destroy_ah call is not sleepable
223215d0a75SBob Pearson 		 */
224215d0a75SBob Pearson 		while (!completion_done(&elem->complete) &&
225215d0a75SBob Pearson 				time_before(jiffies, until))
226215d0a75SBob Pearson 			mdelay(1);
227215d0a75SBob Pearson 
228215d0a75SBob Pearson 		if (WARN_ON(!completion_done(&elem->complete)))
229215d0a75SBob Pearson 			err = -EINVAL;
230215d0a75SBob Pearson 	}
2313225717fSBob Pearson 
2323225717fSBob Pearson 	if (pool->cleanup)
2333225717fSBob Pearson 		pool->cleanup(elem);
2343225717fSBob Pearson 
2353225717fSBob Pearson 	atomic_dec(&pool->num_elem);
236215d0a75SBob Pearson 
237215d0a75SBob Pearson 	return err;
2383225717fSBob Pearson }
2393225717fSBob Pearson 
__rxe_get(struct rxe_pool_elem * elem)2403225717fSBob Pearson int __rxe_get(struct rxe_pool_elem *elem)
2413225717fSBob Pearson {
2423225717fSBob Pearson 	return kref_get_unless_zero(&elem->ref_cnt);
2433225717fSBob Pearson }
2443225717fSBob Pearson 
__rxe_put(struct rxe_pool_elem * elem)2453225717fSBob Pearson int __rxe_put(struct rxe_pool_elem *elem)
2463225717fSBob Pearson {
2473225717fSBob Pearson 	return kref_put(&elem->ref_cnt, rxe_elem_release);
2483225717fSBob Pearson }
249215d0a75SBob Pearson 
__rxe_finalize(struct rxe_pool_elem * elem)250215d0a75SBob Pearson void __rxe_finalize(struct rxe_pool_elem *elem)
251215d0a75SBob Pearson {
252*b54c2a25SBob Pearson 	void *xa_ret;
253215d0a75SBob Pearson 
254*b54c2a25SBob Pearson 	xa_ret = xa_store(&elem->pool->xa, elem->index, elem, GFP_KERNEL);
255*b54c2a25SBob Pearson 	WARN_ON(xa_err(xa_ret));
256215d0a75SBob Pearson }
257