1*608d4f17SYevgeny Kliteynik // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2*608d4f17SYevgeny Kliteynik // Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3*608d4f17SYevgeny Kliteynik 
4*608d4f17SYevgeny Kliteynik #include "dr_types.h"
5*608d4f17SYevgeny Kliteynik 
6*608d4f17SYevgeny Kliteynik #define DR_ICM_MODIFY_HDR_GRANULARITY_4K 12
7*608d4f17SYevgeny Kliteynik 
8*608d4f17SYevgeny Kliteynik /* modify-header arg pool */
9*608d4f17SYevgeny Kliteynik enum dr_arg_chunk_size {
10*608d4f17SYevgeny Kliteynik 	DR_ARG_CHUNK_SIZE_1,
11*608d4f17SYevgeny Kliteynik 	DR_ARG_CHUNK_SIZE_MIN = DR_ARG_CHUNK_SIZE_1, /* keep updated when changing */
12*608d4f17SYevgeny Kliteynik 	DR_ARG_CHUNK_SIZE_2,
13*608d4f17SYevgeny Kliteynik 	DR_ARG_CHUNK_SIZE_3,
14*608d4f17SYevgeny Kliteynik 	DR_ARG_CHUNK_SIZE_4,
15*608d4f17SYevgeny Kliteynik 	DR_ARG_CHUNK_SIZE_MAX,
16*608d4f17SYevgeny Kliteynik };
17*608d4f17SYevgeny Kliteynik 
18*608d4f17SYevgeny Kliteynik /* argument pool area */
19*608d4f17SYevgeny Kliteynik struct dr_arg_pool {
20*608d4f17SYevgeny Kliteynik 	enum dr_arg_chunk_size log_chunk_size;
21*608d4f17SYevgeny Kliteynik 	struct mlx5dr_domain *dmn;
22*608d4f17SYevgeny Kliteynik 	struct list_head free_list;
23*608d4f17SYevgeny Kliteynik 	struct mutex mutex; /* protect arg pool */
24*608d4f17SYevgeny Kliteynik };
25*608d4f17SYevgeny Kliteynik 
26*608d4f17SYevgeny Kliteynik struct mlx5dr_arg_mgr {
27*608d4f17SYevgeny Kliteynik 	struct mlx5dr_domain *dmn;
28*608d4f17SYevgeny Kliteynik 	struct dr_arg_pool *pools[DR_ARG_CHUNK_SIZE_MAX];
29*608d4f17SYevgeny Kliteynik };
30*608d4f17SYevgeny Kliteynik 
dr_arg_pool_alloc_objs(struct dr_arg_pool * pool)31*608d4f17SYevgeny Kliteynik static int dr_arg_pool_alloc_objs(struct dr_arg_pool *pool)
32*608d4f17SYevgeny Kliteynik {
33*608d4f17SYevgeny Kliteynik 	struct mlx5dr_arg_obj *arg_obj, *tmp_arg;
34*608d4f17SYevgeny Kliteynik 	struct list_head cur_list;
35*608d4f17SYevgeny Kliteynik 	u16 object_range;
36*608d4f17SYevgeny Kliteynik 	int num_of_objects;
37*608d4f17SYevgeny Kliteynik 	u32 obj_id = 0;
38*608d4f17SYevgeny Kliteynik 	int i, ret;
39*608d4f17SYevgeny Kliteynik 
40*608d4f17SYevgeny Kliteynik 	INIT_LIST_HEAD(&cur_list);
41*608d4f17SYevgeny Kliteynik 
42*608d4f17SYevgeny Kliteynik 	object_range =
43*608d4f17SYevgeny Kliteynik 		pool->dmn->info.caps.log_header_modify_argument_granularity;
44*608d4f17SYevgeny Kliteynik 
45*608d4f17SYevgeny Kliteynik 	object_range =
46*608d4f17SYevgeny Kliteynik 		max_t(u32, pool->dmn->info.caps.log_header_modify_argument_granularity,
47*608d4f17SYevgeny Kliteynik 		      DR_ICM_MODIFY_HDR_GRANULARITY_4K);
48*608d4f17SYevgeny Kliteynik 	object_range =
49*608d4f17SYevgeny Kliteynik 		min_t(u32, pool->dmn->info.caps.log_header_modify_argument_max_alloc,
50*608d4f17SYevgeny Kliteynik 		      object_range);
51*608d4f17SYevgeny Kliteynik 
52*608d4f17SYevgeny Kliteynik 	if (pool->log_chunk_size > object_range) {
53*608d4f17SYevgeny Kliteynik 		mlx5dr_err(pool->dmn, "Required chunk size (%d) is not supported\n",
54*608d4f17SYevgeny Kliteynik 			   pool->log_chunk_size);
55*608d4f17SYevgeny Kliteynik 		return -ENOMEM;
56*608d4f17SYevgeny Kliteynik 	}
57*608d4f17SYevgeny Kliteynik 
58*608d4f17SYevgeny Kliteynik 	num_of_objects = (1 << (object_range - pool->log_chunk_size));
59*608d4f17SYevgeny Kliteynik 	/* Only one devx object per range */
60*608d4f17SYevgeny Kliteynik 	ret = mlx5dr_cmd_create_modify_header_arg(pool->dmn->mdev,
61*608d4f17SYevgeny Kliteynik 						  object_range,
62*608d4f17SYevgeny Kliteynik 						  pool->dmn->pdn,
63*608d4f17SYevgeny Kliteynik 						  &obj_id);
64*608d4f17SYevgeny Kliteynik 	if (ret) {
65*608d4f17SYevgeny Kliteynik 		mlx5dr_err(pool->dmn, "failed allocating object with range: %d:\n",
66*608d4f17SYevgeny Kliteynik 			   object_range);
67*608d4f17SYevgeny Kliteynik 		return -EAGAIN;
68*608d4f17SYevgeny Kliteynik 	}
69*608d4f17SYevgeny Kliteynik 
70*608d4f17SYevgeny Kliteynik 	for (i = 0; i < num_of_objects; i++) {
71*608d4f17SYevgeny Kliteynik 		arg_obj = kzalloc(sizeof(*arg_obj), GFP_KERNEL);
72*608d4f17SYevgeny Kliteynik 		if (!arg_obj) {
73*608d4f17SYevgeny Kliteynik 			ret = -ENOMEM;
74*608d4f17SYevgeny Kliteynik 			goto clean_arg_obj;
75*608d4f17SYevgeny Kliteynik 		}
76*608d4f17SYevgeny Kliteynik 
77*608d4f17SYevgeny Kliteynik 		arg_obj->log_chunk_size = pool->log_chunk_size;
78*608d4f17SYevgeny Kliteynik 
79*608d4f17SYevgeny Kliteynik 		list_add_tail(&arg_obj->list_node, &cur_list);
80*608d4f17SYevgeny Kliteynik 
81*608d4f17SYevgeny Kliteynik 		arg_obj->obj_id = obj_id;
82*608d4f17SYevgeny Kliteynik 		arg_obj->obj_offset = i * (1 << pool->log_chunk_size);
83*608d4f17SYevgeny Kliteynik 	}
84*608d4f17SYevgeny Kliteynik 	list_splice_tail_init(&cur_list, &pool->free_list);
85*608d4f17SYevgeny Kliteynik 
86*608d4f17SYevgeny Kliteynik 	return 0;
87*608d4f17SYevgeny Kliteynik 
88*608d4f17SYevgeny Kliteynik clean_arg_obj:
89*608d4f17SYevgeny Kliteynik 	mlx5dr_cmd_destroy_modify_header_arg(pool->dmn->mdev, obj_id);
90*608d4f17SYevgeny Kliteynik 	list_for_each_entry_safe(arg_obj, tmp_arg, &cur_list, list_node) {
91*608d4f17SYevgeny Kliteynik 		list_del(&arg_obj->list_node);
92*608d4f17SYevgeny Kliteynik 		kfree(arg_obj);
93*608d4f17SYevgeny Kliteynik 	}
94*608d4f17SYevgeny Kliteynik 	return ret;
95*608d4f17SYevgeny Kliteynik }
96*608d4f17SYevgeny Kliteynik 
dr_arg_pool_get_arg_obj(struct dr_arg_pool * pool)97*608d4f17SYevgeny Kliteynik static struct mlx5dr_arg_obj *dr_arg_pool_get_arg_obj(struct dr_arg_pool *pool)
98*608d4f17SYevgeny Kliteynik {
99*608d4f17SYevgeny Kliteynik 	struct mlx5dr_arg_obj *arg_obj = NULL;
100*608d4f17SYevgeny Kliteynik 	int ret;
101*608d4f17SYevgeny Kliteynik 
102*608d4f17SYevgeny Kliteynik 	mutex_lock(&pool->mutex);
103*608d4f17SYevgeny Kliteynik 	if (list_empty(&pool->free_list)) {
104*608d4f17SYevgeny Kliteynik 		ret = dr_arg_pool_alloc_objs(pool);
105*608d4f17SYevgeny Kliteynik 		if (ret)
106*608d4f17SYevgeny Kliteynik 			goto out;
107*608d4f17SYevgeny Kliteynik 	}
108*608d4f17SYevgeny Kliteynik 
109*608d4f17SYevgeny Kliteynik 	arg_obj = list_first_entry_or_null(&pool->free_list,
110*608d4f17SYevgeny Kliteynik 					   struct mlx5dr_arg_obj,
111*608d4f17SYevgeny Kliteynik 					   list_node);
112*608d4f17SYevgeny Kliteynik 	WARN(!arg_obj, "couldn't get dr arg obj from pool");
113*608d4f17SYevgeny Kliteynik 
114*608d4f17SYevgeny Kliteynik 	if (arg_obj)
115*608d4f17SYevgeny Kliteynik 		list_del_init(&arg_obj->list_node);
116*608d4f17SYevgeny Kliteynik 
117*608d4f17SYevgeny Kliteynik out:
118*608d4f17SYevgeny Kliteynik 	mutex_unlock(&pool->mutex);
119*608d4f17SYevgeny Kliteynik 	return arg_obj;
120*608d4f17SYevgeny Kliteynik }
121*608d4f17SYevgeny Kliteynik 
dr_arg_pool_put_arg_obj(struct dr_arg_pool * pool,struct mlx5dr_arg_obj * arg_obj)122*608d4f17SYevgeny Kliteynik static void dr_arg_pool_put_arg_obj(struct dr_arg_pool *pool,
123*608d4f17SYevgeny Kliteynik 				    struct mlx5dr_arg_obj *arg_obj)
124*608d4f17SYevgeny Kliteynik {
125*608d4f17SYevgeny Kliteynik 	mutex_lock(&pool->mutex);
126*608d4f17SYevgeny Kliteynik 	list_add(&arg_obj->list_node, &pool->free_list);
127*608d4f17SYevgeny Kliteynik 	mutex_unlock(&pool->mutex);
128*608d4f17SYevgeny Kliteynik }
129*608d4f17SYevgeny Kliteynik 
dr_arg_pool_create(struct mlx5dr_domain * dmn,enum dr_arg_chunk_size chunk_size)130*608d4f17SYevgeny Kliteynik static struct dr_arg_pool *dr_arg_pool_create(struct mlx5dr_domain *dmn,
131*608d4f17SYevgeny Kliteynik 					      enum dr_arg_chunk_size chunk_size)
132*608d4f17SYevgeny Kliteynik {
133*608d4f17SYevgeny Kliteynik 	struct dr_arg_pool *pool;
134*608d4f17SYevgeny Kliteynik 
135*608d4f17SYevgeny Kliteynik 	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
136*608d4f17SYevgeny Kliteynik 	if (!pool)
137*608d4f17SYevgeny Kliteynik 		return NULL;
138*608d4f17SYevgeny Kliteynik 
139*608d4f17SYevgeny Kliteynik 	pool->dmn = dmn;
140*608d4f17SYevgeny Kliteynik 
141*608d4f17SYevgeny Kliteynik 	INIT_LIST_HEAD(&pool->free_list);
142*608d4f17SYevgeny Kliteynik 	mutex_init(&pool->mutex);
143*608d4f17SYevgeny Kliteynik 
144*608d4f17SYevgeny Kliteynik 	pool->log_chunk_size = chunk_size;
145*608d4f17SYevgeny Kliteynik 	if (dr_arg_pool_alloc_objs(pool))
146*608d4f17SYevgeny Kliteynik 		goto free_pool;
147*608d4f17SYevgeny Kliteynik 
148*608d4f17SYevgeny Kliteynik 	return pool;
149*608d4f17SYevgeny Kliteynik 
150*608d4f17SYevgeny Kliteynik free_pool:
151*608d4f17SYevgeny Kliteynik 	kfree(pool);
152*608d4f17SYevgeny Kliteynik 
153*608d4f17SYevgeny Kliteynik 	return NULL;
154*608d4f17SYevgeny Kliteynik }
155*608d4f17SYevgeny Kliteynik 
dr_arg_pool_destroy(struct dr_arg_pool * pool)156*608d4f17SYevgeny Kliteynik static void dr_arg_pool_destroy(struct dr_arg_pool *pool)
157*608d4f17SYevgeny Kliteynik {
158*608d4f17SYevgeny Kliteynik 	struct mlx5dr_arg_obj *arg_obj, *tmp_arg;
159*608d4f17SYevgeny Kliteynik 
160*608d4f17SYevgeny Kliteynik 	list_for_each_entry_safe(arg_obj, tmp_arg, &pool->free_list, list_node) {
161*608d4f17SYevgeny Kliteynik 		list_del(&arg_obj->list_node);
162*608d4f17SYevgeny Kliteynik 		if (!arg_obj->obj_offset) /* the first in range */
163*608d4f17SYevgeny Kliteynik 			mlx5dr_cmd_destroy_modify_header_arg(pool->dmn->mdev, arg_obj->obj_id);
164*608d4f17SYevgeny Kliteynik 		kfree(arg_obj);
165*608d4f17SYevgeny Kliteynik 	}
166*608d4f17SYevgeny Kliteynik 
167*608d4f17SYevgeny Kliteynik 	mutex_destroy(&pool->mutex);
168*608d4f17SYevgeny Kliteynik 	kfree(pool);
169*608d4f17SYevgeny Kliteynik }
170*608d4f17SYevgeny Kliteynik 
dr_arg_get_chunk_size(u16 num_of_actions)171*608d4f17SYevgeny Kliteynik static enum dr_arg_chunk_size dr_arg_get_chunk_size(u16 num_of_actions)
172*608d4f17SYevgeny Kliteynik {
173*608d4f17SYevgeny Kliteynik 	if (num_of_actions <= 8)
174*608d4f17SYevgeny Kliteynik 		return DR_ARG_CHUNK_SIZE_1;
175*608d4f17SYevgeny Kliteynik 	if (num_of_actions <= 16)
176*608d4f17SYevgeny Kliteynik 		return DR_ARG_CHUNK_SIZE_2;
177*608d4f17SYevgeny Kliteynik 	if (num_of_actions <= 32)
178*608d4f17SYevgeny Kliteynik 		return DR_ARG_CHUNK_SIZE_3;
179*608d4f17SYevgeny Kliteynik 	if (num_of_actions <= 64)
180*608d4f17SYevgeny Kliteynik 		return DR_ARG_CHUNK_SIZE_4;
181*608d4f17SYevgeny Kliteynik 
182*608d4f17SYevgeny Kliteynik 	return DR_ARG_CHUNK_SIZE_MAX;
183*608d4f17SYevgeny Kliteynik }
184*608d4f17SYevgeny Kliteynik 
mlx5dr_arg_get_obj_id(struct mlx5dr_arg_obj * arg_obj)185*608d4f17SYevgeny Kliteynik u32 mlx5dr_arg_get_obj_id(struct mlx5dr_arg_obj *arg_obj)
186*608d4f17SYevgeny Kliteynik {
187*608d4f17SYevgeny Kliteynik 	return (arg_obj->obj_id + arg_obj->obj_offset);
188*608d4f17SYevgeny Kliteynik }
189*608d4f17SYevgeny Kliteynik 
mlx5dr_arg_get_obj(struct mlx5dr_arg_mgr * mgr,u16 num_of_actions,u8 * data)190*608d4f17SYevgeny Kliteynik struct mlx5dr_arg_obj *mlx5dr_arg_get_obj(struct mlx5dr_arg_mgr *mgr,
191*608d4f17SYevgeny Kliteynik 					  u16 num_of_actions,
192*608d4f17SYevgeny Kliteynik 					  u8 *data)
193*608d4f17SYevgeny Kliteynik {
194*608d4f17SYevgeny Kliteynik 	u32 size = dr_arg_get_chunk_size(num_of_actions);
195*608d4f17SYevgeny Kliteynik 	struct mlx5dr_arg_obj *arg_obj;
196*608d4f17SYevgeny Kliteynik 	int ret;
197*608d4f17SYevgeny Kliteynik 
198*608d4f17SYevgeny Kliteynik 	if (size >= DR_ARG_CHUNK_SIZE_MAX)
199*608d4f17SYevgeny Kliteynik 		return NULL;
200*608d4f17SYevgeny Kliteynik 
201*608d4f17SYevgeny Kliteynik 	arg_obj = dr_arg_pool_get_arg_obj(mgr->pools[size]);
202*608d4f17SYevgeny Kliteynik 	if (!arg_obj) {
203*608d4f17SYevgeny Kliteynik 		mlx5dr_err(mgr->dmn, "Failed allocating args object for modify header\n");
204*608d4f17SYevgeny Kliteynik 		return NULL;
205*608d4f17SYevgeny Kliteynik 	}
206*608d4f17SYevgeny Kliteynik 
207*608d4f17SYevgeny Kliteynik 	/* write it into the hw */
208*608d4f17SYevgeny Kliteynik 	ret = mlx5dr_send_postsend_args(mgr->dmn,
209*608d4f17SYevgeny Kliteynik 					mlx5dr_arg_get_obj_id(arg_obj),
210*608d4f17SYevgeny Kliteynik 					num_of_actions, data);
211*608d4f17SYevgeny Kliteynik 	if (ret) {
212*608d4f17SYevgeny Kliteynik 		mlx5dr_err(mgr->dmn, "Failed writing args object\n");
213*608d4f17SYevgeny Kliteynik 		goto put_obj;
214*608d4f17SYevgeny Kliteynik 	}
215*608d4f17SYevgeny Kliteynik 
216*608d4f17SYevgeny Kliteynik 	return arg_obj;
217*608d4f17SYevgeny Kliteynik 
218*608d4f17SYevgeny Kliteynik put_obj:
219*608d4f17SYevgeny Kliteynik 	mlx5dr_arg_put_obj(mgr, arg_obj);
220*608d4f17SYevgeny Kliteynik 	return NULL;
221*608d4f17SYevgeny Kliteynik }
222*608d4f17SYevgeny Kliteynik 
mlx5dr_arg_put_obj(struct mlx5dr_arg_mgr * mgr,struct mlx5dr_arg_obj * arg_obj)223*608d4f17SYevgeny Kliteynik void mlx5dr_arg_put_obj(struct mlx5dr_arg_mgr *mgr,
224*608d4f17SYevgeny Kliteynik 			struct mlx5dr_arg_obj *arg_obj)
225*608d4f17SYevgeny Kliteynik {
226*608d4f17SYevgeny Kliteynik 	dr_arg_pool_put_arg_obj(mgr->pools[arg_obj->log_chunk_size], arg_obj);
227*608d4f17SYevgeny Kliteynik }
228*608d4f17SYevgeny Kliteynik 
229*608d4f17SYevgeny Kliteynik struct mlx5dr_arg_mgr*
mlx5dr_arg_mgr_create(struct mlx5dr_domain * dmn)230*608d4f17SYevgeny Kliteynik mlx5dr_arg_mgr_create(struct mlx5dr_domain *dmn)
231*608d4f17SYevgeny Kliteynik {
232*608d4f17SYevgeny Kliteynik 	struct mlx5dr_arg_mgr *pool_mgr;
233*608d4f17SYevgeny Kliteynik 	int i;
234*608d4f17SYevgeny Kliteynik 
235*608d4f17SYevgeny Kliteynik 	if (!mlx5dr_domain_is_support_ptrn_arg(dmn))
236*608d4f17SYevgeny Kliteynik 		return NULL;
237*608d4f17SYevgeny Kliteynik 
238*608d4f17SYevgeny Kliteynik 	pool_mgr = kzalloc(sizeof(*pool_mgr), GFP_KERNEL);
239*608d4f17SYevgeny Kliteynik 	if (!pool_mgr)
240*608d4f17SYevgeny Kliteynik 		return NULL;
241*608d4f17SYevgeny Kliteynik 
242*608d4f17SYevgeny Kliteynik 	pool_mgr->dmn = dmn;
243*608d4f17SYevgeny Kliteynik 
244*608d4f17SYevgeny Kliteynik 	for (i = 0; i < DR_ARG_CHUNK_SIZE_MAX; i++) {
245*608d4f17SYevgeny Kliteynik 		pool_mgr->pools[i] = dr_arg_pool_create(dmn, i);
246*608d4f17SYevgeny Kliteynik 		if (!pool_mgr->pools[i])
247*608d4f17SYevgeny Kliteynik 			goto clean_pools;
248*608d4f17SYevgeny Kliteynik 	}
249*608d4f17SYevgeny Kliteynik 
250*608d4f17SYevgeny Kliteynik 	return pool_mgr;
251*608d4f17SYevgeny Kliteynik 
252*608d4f17SYevgeny Kliteynik clean_pools:
253*608d4f17SYevgeny Kliteynik 	for (i--; i >= 0; i--)
254*608d4f17SYevgeny Kliteynik 		dr_arg_pool_destroy(pool_mgr->pools[i]);
255*608d4f17SYevgeny Kliteynik 
256*608d4f17SYevgeny Kliteynik 	kfree(pool_mgr);
257*608d4f17SYevgeny Kliteynik 	return NULL;
258*608d4f17SYevgeny Kliteynik }
259*608d4f17SYevgeny Kliteynik 
mlx5dr_arg_mgr_destroy(struct mlx5dr_arg_mgr * mgr)260*608d4f17SYevgeny Kliteynik void mlx5dr_arg_mgr_destroy(struct mlx5dr_arg_mgr *mgr)
261*608d4f17SYevgeny Kliteynik {
262*608d4f17SYevgeny Kliteynik 	struct dr_arg_pool **pools;
263*608d4f17SYevgeny Kliteynik 	int i;
264*608d4f17SYevgeny Kliteynik 
265*608d4f17SYevgeny Kliteynik 	if (!mgr)
266*608d4f17SYevgeny Kliteynik 		return;
267*608d4f17SYevgeny Kliteynik 
268*608d4f17SYevgeny Kliteynik 	pools = mgr->pools;
269*608d4f17SYevgeny Kliteynik 	for (i = 0; i < DR_ARG_CHUNK_SIZE_MAX; i++)
270*608d4f17SYevgeny Kliteynik 		dr_arg_pool_destroy(pools[i]);
271*608d4f17SYevgeny Kliteynik 
272*608d4f17SYevgeny Kliteynik 	kfree(mgr);
273*608d4f17SYevgeny Kliteynik }
274