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