Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3 : : */
4 : :
5 : : #include "mlx5dr_internal.h"
6 : :
7 : : static int
8 : : table_type_to_root_action_flags(enum mlx5dr_table_type table_type,
9 : : enum mlx5dr_action_flags *out)
10 : : {
11 [ # # # # ]: 0 : switch (table_type) {
12 : 0 : case MLX5DR_TABLE_TYPE_NIC_RX:
13 : 0 : *out = MLX5DR_ACTION_FLAG_ROOT_RX;
14 : : break;
15 : 0 : case MLX5DR_TABLE_TYPE_NIC_TX:
16 : 0 : *out = MLX5DR_ACTION_FLAG_ROOT_TX;
17 : : break;
18 : 0 : case MLX5DR_TABLE_TYPE_FDB:
19 : 0 : *out = MLX5DR_ACTION_FLAG_ROOT_FDB;
20 : : break;
21 : 0 : default:
22 : 0 : rte_errno = EINVAL;
23 : : return -rte_errno;
24 : : }
25 : :
26 : : return 0;
27 : : }
28 : :
29 : : static int
30 : : table_type_to_nonroot_action_flags(enum mlx5dr_table_type table_type,
31 : : enum mlx5dr_action_flags *out)
32 : : {
33 [ # # # # : 0 : switch (table_type) {
# # # ]
34 : 0 : case MLX5DR_TABLE_TYPE_NIC_RX:
35 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_RX;
36 : : break;
37 : 0 : case MLX5DR_TABLE_TYPE_NIC_TX:
38 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_TX;
39 : : break;
40 : 0 : case MLX5DR_TABLE_TYPE_FDB:
41 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_FDB;
42 : : break;
43 : 0 : case MLX5DR_TABLE_TYPE_FDB_RX:
44 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_FDB_RX;
45 : : break;
46 : 0 : case MLX5DR_TABLE_TYPE_FDB_TX:
47 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_FDB_TX;
48 : : break;
49 : 0 : case MLX5DR_TABLE_TYPE_FDB_UNIFIED:
50 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_FDB_UNIFIED;
51 : : break;
52 : 0 : default:
53 : 0 : rte_errno = EINVAL;
54 : : return -rte_errno;
55 : : }
56 : :
57 : : return 0;
58 : : }
59 : :
60 : : int
61 : 0 : mlx5dr_table_type_to_action_flags(const enum mlx5dr_table_type table_type,
62 : : const bool is_root,
63 : : enum mlx5dr_action_flags *action_flags)
64 : : {
65 : : int ret = 0;
66 : :
67 [ # # ]: 0 : if (is_root) {
68 : : ret = table_type_to_root_action_flags(table_type, action_flags);
69 : : if (ret < 0)
70 : 0 : DR_LOG(ERR, "Cannot convert table type %d to action flags for root table",
71 : : table_type);
72 : : } else {
73 : : ret = table_type_to_nonroot_action_flags(table_type, action_flags);
74 : : if (ret < 0)
75 : 0 : DR_LOG(ERR, "Cannot convert table type %d to action flags for HWS table",
76 : : table_type);
77 : : }
78 : :
79 : 0 : return ret;
80 : : }
81 : :
82 : 0 : static void mlx5dr_table_init_next_ft_attr(struct mlx5dr_table *tbl,
83 : : struct mlx5dr_cmd_ft_create_attr *ft_attr)
84 : : {
85 : 0 : ft_attr->type = tbl->fw_ft_type;
86 [ # # ]: 0 : if (mlx5dr_table_is_fdb_any(tbl->type))
87 : 0 : ft_attr->level = tbl->ctx->caps->fdb_ft.max_level - 1;
88 : : else
89 : 0 : ft_attr->level = tbl->ctx->caps->nic_ft.max_level - 1;
90 : 0 : ft_attr->rtc_valid = true;
91 : 0 : }
92 : :
93 : : /* Call this under ctx->ctrl_lock */
94 : : static int
95 : 0 : mlx5dr_table_up_default_fdb_miss_tbl(struct mlx5dr_table *tbl)
96 : : {
97 : 0 : struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
98 : 0 : struct mlx5dr_cmd_set_fte_attr fte_attr = {0};
99 : : struct mlx5dr_cmd_forward_tbl *default_miss;
100 : 0 : struct mlx5dr_cmd_set_fte_dest dest = {0};
101 : 0 : struct mlx5dr_context *ctx = tbl->ctx;
102 [ # # ]: 0 : uint8_t tbl_type = tbl->type;
103 : :
104 : : if (!mlx5dr_table_is_fdb_any(tbl_type))
105 : : return 0;
106 : :
107 [ # # ]: 0 : if (ctx->common_res[tbl_type].default_miss) {
108 : 0 : ctx->common_res[tbl_type].default_miss->refcount++;
109 : 0 : return 0;
110 : : }
111 : :
112 : 0 : ft_attr.type = tbl->fw_ft_type;
113 : 0 : ft_attr.level = tbl->ctx->caps->fdb_ft.max_level; /* The last level */
114 : : ft_attr.rtc_valid = false;
115 : :
116 : : dest.destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
117 : 0 : dest.destination_id = ctx->caps->eswitch_manager_vport_number;
118 : 0 : fte_attr.action_flags = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
119 : 0 : fte_attr.dests_num = 1;
120 [ # # ]: 0 : fte_attr.dests = &dest;
121 : :
122 : 0 : default_miss = mlx5dr_cmd_forward_tbl_create(mlx5dr_context_get_local_ibv(ctx),
123 : : &ft_attr, &fte_attr);
124 [ # # ]: 0 : if (!default_miss) {
125 : 0 : DR_LOG(ERR, "Failed to default miss table type: 0x%x", tbl_type);
126 : 0 : return rte_errno;
127 : : }
128 : :
129 : 0 : ctx->common_res[tbl_type].default_miss = default_miss;
130 : 0 : ctx->common_res[tbl_type].default_miss->refcount++;
131 : 0 : return 0;
132 : : }
133 : :
134 : : /* Called under pthread_spin_lock(&ctx->ctrl_lock) */
135 : 0 : static void mlx5dr_table_down_default_fdb_miss_tbl(struct mlx5dr_table *tbl)
136 : : {
137 : : struct mlx5dr_cmd_forward_tbl *default_miss;
138 : 0 : struct mlx5dr_context *ctx = tbl->ctx;
139 [ # # ]: 0 : uint8_t tbl_type = tbl->type;
140 : :
141 : : if (!mlx5dr_table_is_fdb_any(tbl->type))
142 : : return;
143 : :
144 : 0 : default_miss = ctx->common_res[tbl_type].default_miss;
145 [ # # ]: 0 : if (--default_miss->refcount)
146 : : return;
147 : :
148 : 0 : mlx5dr_cmd_forward_tbl_destroy(default_miss);
149 : 0 : ctx->common_res[tbl_type].default_miss = NULL;
150 : : }
151 : :
152 : : static int
153 : 0 : mlx5dr_table_connect_to_default_miss_tbl(struct mlx5dr_table *tbl,
154 : : struct mlx5dr_devx_obj *ft)
155 : : {
156 : 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
157 : : int ret;
158 : :
159 [ # # ]: 0 : assert(mlx5dr_table_is_fdb_any(tbl->type));
160 : :
161 : 0 : mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx,
162 : : tbl->fw_ft_type,
163 : : tbl->type,
164 : : &ft_attr);
165 : :
166 : : /* Connect to next */
167 : 0 : ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
168 [ # # ]: 0 : if (ret) {
169 : 0 : DR_LOG(ERR, "Failed to connect FT to default FDB FT");
170 : 0 : return ret;
171 : : }
172 : :
173 : : return 0;
174 : : }
175 : :
176 : : struct mlx5dr_devx_obj *
177 : 0 : mlx5dr_table_create_default_ft(struct ibv_context *ibv,
178 : : struct mlx5dr_table *tbl)
179 : : {
180 : 0 : struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
181 : : struct mlx5dr_devx_obj *ft_obj;
182 : : int ret;
183 : :
184 : 0 : mlx5dr_table_init_next_ft_attr(tbl, &ft_attr);
185 : :
186 : 0 : ft_obj = mlx5dr_cmd_flow_table_create(ibv, &ft_attr);
187 [ # # # # ]: 0 : if (ft_obj && mlx5dr_table_is_fdb_any(tbl->type)) {
188 : : /* Take/create ref over the default miss */
189 : 0 : ret = mlx5dr_table_up_default_fdb_miss_tbl(tbl);
190 [ # # ]: 0 : if (ret) {
191 : 0 : DR_LOG(ERR, "Failed to get default fdb miss for type: %d\n",
192 : : tbl->type);
193 : 0 : goto free_ft_obj;
194 : : }
195 : 0 : ret = mlx5dr_table_connect_to_default_miss_tbl(tbl, ft_obj);
196 [ # # ]: 0 : if (ret) {
197 : 0 : DR_LOG(ERR, "Failed connecting to default miss tbl (type: %d)",
198 : : tbl->type);
199 : 0 : goto down_miss_tbl;
200 : : }
201 : : }
202 : :
203 : : return ft_obj;
204 : :
205 : : down_miss_tbl:
206 : 0 : mlx5dr_table_down_default_fdb_miss_tbl(tbl);
207 : 0 : free_ft_obj:
208 : 0 : mlx5dr_cmd_destroy_obj(ft_obj);
209 : 0 : return NULL;
210 : : }
211 : :
212 : : static int
213 : 0 : mlx5dr_table_init_check_hws_support(struct mlx5dr_context *ctx,
214 : : struct mlx5dr_table *tbl)
215 : : {
216 [ # # ]: 0 : if (!(ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT)) {
217 : 0 : DR_LOG(ERR, "HWS not supported, cannot create mlx5dr_table");
218 : 0 : rte_errno = EOPNOTSUPP;
219 : 0 : return rte_errno;
220 : : }
221 : :
222 [ # # # # ]: 0 : if (mlx5dr_context_shared_gvmi_used(ctx) && mlx5dr_table_is_fdb_any(tbl->type)) {
223 : 0 : DR_LOG(ERR, "FDB with shared port resources is not supported");
224 : 0 : rte_errno = EOPNOTSUPP;
225 : 0 : return rte_errno;
226 : : }
227 : :
228 : : return 0;
229 : : }
230 : :
231 : : static int
232 : 0 : mlx5dr_table_shared_gvmi_resource_create(struct mlx5dr_context *ctx,
233 : : enum mlx5dr_table_type type,
234 : : struct mlx5dr_context_shared_gvmi_res *gvmi_res)
235 : : {
236 [ # # ]: 0 : struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
237 : : uint32_t calculated_ft_id;
238 : : int ret;
239 : :
240 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
241 : : return 0;
242 : :
243 : 0 : ft_attr.type = mlx5dr_table_get_res_fw_ft_type(type, false);
244 : 0 : ft_attr.level = ctx->caps->nic_ft.max_level - 1;
245 : 0 : ft_attr.rtc_valid = true;
246 : :
247 : 0 : gvmi_res->end_ft =
248 : 0 : mlx5dr_cmd_flow_table_create(mlx5dr_context_get_local_ibv(ctx),
249 : : &ft_attr);
250 [ # # ]: 0 : if (!gvmi_res->end_ft) {
251 : 0 : DR_LOG(ERR, "Failed to create end-ft");
252 : 0 : return rte_errno;
253 : : }
254 : :
255 : 0 : calculated_ft_id =
256 : 0 : mlx5dr_table_get_res_fw_ft_type(type, false) << FT_ID_FT_TYPE_OFFSET;
257 : 0 : calculated_ft_id |= gvmi_res->end_ft->id;
258 : :
259 : : /* create alias to that FT */
260 : 0 : ret = mlx5dr_matcher_create_aliased_obj(ctx,
261 : : ctx->local_ibv_ctx,
262 : : ctx->ibv_ctx,
263 : 0 : ctx->caps->vhca_id,
264 : : calculated_ft_id,
265 : : MLX5_GENERAL_OBJ_TYPE_FT_ALIAS,
266 : : &gvmi_res->aliased_end_ft);
267 [ # # ]: 0 : if (ret) {
268 : 0 : DR_LOG(ERR, "Failed to create alias end-ft");
269 : 0 : goto free_end_ft;
270 : : }
271 : :
272 : : return 0;
273 : :
274 : : free_end_ft:
275 : 0 : mlx5dr_cmd_destroy_obj(gvmi_res->end_ft);
276 : :
277 : 0 : return rte_errno;
278 : : }
279 : :
280 : : static void
281 [ # # ]: 0 : mlx5dr_table_shared_gvmi_resourse_destroy(struct mlx5dr_context *ctx,
282 : : struct mlx5dr_context_shared_gvmi_res *gvmi_res)
283 : : {
284 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
285 : : return;
286 : :
287 [ # # ]: 0 : if (gvmi_res->aliased_end_ft) {
288 : 0 : mlx5dr_cmd_destroy_obj(gvmi_res->aliased_end_ft);
289 : 0 : gvmi_res->aliased_end_ft = NULL;
290 : : }
291 [ # # ]: 0 : if (gvmi_res->end_ft) {
292 : 0 : mlx5dr_cmd_destroy_obj(gvmi_res->end_ft);
293 : 0 : gvmi_res->end_ft = NULL;
294 : : }
295 : : }
296 : :
297 : : /* called under spinlock ctx->ctrl_lock */
298 : : static struct mlx5dr_context_shared_gvmi_res *
299 [ # # ]: 0 : mlx5dr_table_get_shared_gvmi_res(struct mlx5dr_context *ctx, enum mlx5dr_table_type type)
300 : : {
301 : : int ret;
302 : :
303 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
304 : : return NULL;
305 : :
306 [ # # ]: 0 : if (ctx->gvmi_res[type].aliased_end_ft) {
307 : 0 : ctx->gvmi_res[type].refcount++;
308 : 0 : return &ctx->gvmi_res[type];
309 : : }
310 : :
311 : 0 : ret = mlx5dr_table_shared_gvmi_resource_create(ctx, type, &ctx->gvmi_res[type]);
312 [ # # ]: 0 : if (ret) {
313 : 0 : DR_LOG(ERR, "Failed to create shared gvmi res for type: %d", type);
314 : 0 : goto out;
315 : : }
316 : :
317 : 0 : ctx->gvmi_res[type].refcount = 1;
318 : :
319 : 0 : return &ctx->gvmi_res[type];
320 : :
321 : : out:
322 : 0 : return NULL;
323 : : }
324 : :
325 : : /* called under spinlock ctx->ctrl_lock */
326 : 0 : static void mlx5dr_table_put_shared_gvmi_res(struct mlx5dr_table *tbl)
327 : : {
328 [ # # ]: 0 : struct mlx5dr_context *ctx = tbl->ctx;
329 : :
330 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
331 : : return;
332 : :
333 [ # # ]: 0 : if (--ctx->gvmi_res[tbl->type].refcount)
334 : : return;
335 : :
336 : 0 : mlx5dr_table_shared_gvmi_resourse_destroy(ctx, &ctx->gvmi_res[tbl->type]);
337 : : }
338 : :
339 : 0 : static void mlx5dr_table_uninit_shared_ctx_res(struct mlx5dr_table *tbl)
340 : : {
341 [ # # ]: 0 : struct mlx5dr_context *ctx = tbl->ctx;
342 : :
343 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
344 : : return;
345 : :
346 : 0 : mlx5dr_cmd_destroy_obj(tbl->local_ft);
347 : :
348 : 0 : mlx5dr_table_put_shared_gvmi_res(tbl);
349 : : }
350 : :
351 : : /* called under spin_lock ctx->ctrl_lock */
352 : 0 : static int mlx5dr_table_init_shared_ctx_res(struct mlx5dr_context *ctx, struct mlx5dr_table *tbl)
353 : : {
354 [ # # ]: 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
355 : : int ret;
356 : :
357 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
358 : : return 0;
359 : :
360 : : /* create local-ft for root access */
361 : 0 : tbl->local_ft =
362 : 0 : mlx5dr_table_create_default_ft(mlx5dr_context_get_local_ibv(ctx), tbl);
363 [ # # ]: 0 : if (!tbl->local_ft) {
364 : 0 : DR_LOG(ERR, "Failed to create local-ft");
365 : 0 : return rte_errno;
366 : : }
367 : :
368 [ # # ]: 0 : if (!mlx5dr_table_get_shared_gvmi_res(tbl->ctx, tbl->type)) {
369 : 0 : DR_LOG(ERR, "Failed to shared gvmi resources");
370 : 0 : goto clean_local_ft;
371 : : }
372 : :
373 : : /* On shared gvmi the default behavior is jump to alias end ft */
374 : 0 : mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx,
375 : : tbl->fw_ft_type,
376 : : tbl->type,
377 : : &ft_attr);
378 : :
379 : 0 : ret = mlx5dr_cmd_flow_table_modify(tbl->ft, &ft_attr);
380 [ # # ]: 0 : if (ret) {
381 : 0 : DR_LOG(ERR, "Failed to point table to its default miss");
382 : 0 : goto clean_shared_res;
383 : : }
384 : :
385 : : return 0;
386 : :
387 : : clean_shared_res:
388 : 0 : mlx5dr_table_put_shared_gvmi_res(tbl);
389 : 0 : clean_local_ft:
390 : 0 : mlx5dr_table_destroy_default_ft(tbl, tbl->local_ft);
391 : 0 : return rte_errno;
392 : : }
393 : :
394 : 0 : void mlx5dr_table_destroy_default_ft(struct mlx5dr_table *tbl,
395 : : struct mlx5dr_devx_obj *ft_obj)
396 : : {
397 : 0 : mlx5dr_cmd_destroy_obj(ft_obj);
398 : 0 : mlx5dr_table_down_default_fdb_miss_tbl(tbl);
399 : 0 : }
400 : :
401 : 0 : static int mlx5dr_table_init(struct mlx5dr_table *tbl)
402 : : {
403 [ # # ]: 0 : struct mlx5dr_context *ctx = tbl->ctx;
404 : : int ret;
405 : :
406 [ # # ]: 0 : if (mlx5dr_table_is_root(tbl))
407 : : return 0;
408 : :
409 : 0 : ret = mlx5dr_table_init_check_hws_support(ctx, tbl);
410 [ # # ]: 0 : if (ret)
411 : : return ret;
412 : :
413 : 0 : mlx5dr_table_get_fw_ft_type(tbl->type, (uint8_t *)&tbl->fw_ft_type);
414 : :
415 : 0 : pthread_spin_lock(&ctx->ctrl_lock);
416 : 0 : tbl->ft = mlx5dr_table_create_default_ft(tbl->ctx->ibv_ctx, tbl);
417 [ # # ]: 0 : if (!tbl->ft) {
418 : 0 : DR_LOG(ERR, "Failed to create flow table devx object");
419 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
420 : 0 : return rte_errno;
421 : : }
422 : :
423 : 0 : ret = mlx5dr_table_init_shared_ctx_res(ctx, tbl);
424 [ # # ]: 0 : if (ret)
425 : 0 : goto tbl_destroy;
426 : :
427 : 0 : ret = mlx5dr_action_get_default_stc(ctx, tbl->type);
428 [ # # ]: 0 : if (ret)
429 : 0 : goto free_shared_ctx;
430 : :
431 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
432 : :
433 : 0 : return 0;
434 : :
435 : : free_shared_ctx:
436 : 0 : mlx5dr_table_uninit_shared_ctx_res(tbl);
437 : 0 : tbl_destroy:
438 : 0 : mlx5dr_table_destroy_default_ft(tbl, tbl->ft);
439 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
440 : 0 : return rte_errno;
441 : : }
442 : :
443 [ # # ]: 0 : static void mlx5dr_table_uninit(struct mlx5dr_table *tbl)
444 : : {
445 [ # # ]: 0 : if (mlx5dr_table_is_root(tbl))
446 : : return;
447 : 0 : pthread_spin_lock(&tbl->ctx->ctrl_lock);
448 : 0 : mlx5dr_action_put_default_stc(tbl->ctx, tbl->type);
449 : 0 : mlx5dr_table_uninit_shared_ctx_res(tbl);
450 : 0 : mlx5dr_table_destroy_default_ft(tbl, tbl->ft);
451 : 0 : pthread_spin_unlock(&tbl->ctx->ctrl_lock);
452 : : }
453 : :
454 : 0 : struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_context *ctx,
455 : : struct mlx5dr_table_attr *attr)
456 : : {
457 : : struct mlx5dr_table *tbl;
458 : : int ret;
459 : :
460 [ # # ]: 0 : if (attr->type >= MLX5DR_TABLE_TYPE_MAX) {
461 : 0 : DR_LOG(ERR, "Invalid table type %d", attr->type);
462 : 0 : return NULL;
463 : : }
464 : :
465 [ # # # # ]: 0 : if (attr->type == MLX5DR_TABLE_TYPE_FDB_UNIFIED && !ctx->caps->fdb_unified_en) {
466 : 0 : DR_LOG(ERR, "Table type %d not supported by current FW", attr->type);
467 : 0 : rte_errno = ENOTSUP;
468 : 0 : return NULL;
469 : : }
470 : :
471 [ # # ]: 0 : if ((mlx5dr_table_is_fdb_any(attr->type) && attr->type != MLX5DR_TABLE_TYPE_FDB) &&
472 [ # # ]: 0 : !attr->level) {
473 : 0 : DR_LOG(ERR, "Table type %d not supported by root table", attr->type);
474 : 0 : rte_errno = ENOTSUP;
475 : 0 : return NULL;
476 : : }
477 : :
478 : : tbl = simple_calloc(1, sizeof(*tbl));
479 [ # # ]: 0 : if (!tbl) {
480 : 0 : rte_errno = ENOMEM;
481 : 0 : return NULL;
482 : : }
483 : :
484 : 0 : tbl->ctx = ctx;
485 : 0 : tbl->type = attr->type;
486 : 0 : tbl->level = attr->level;
487 : :
488 : 0 : ret = mlx5dr_table_init(tbl);
489 [ # # ]: 0 : if (ret) {
490 : 0 : DR_LOG(ERR, "Failed to initialise table");
491 : 0 : goto free_tbl;
492 : : }
493 : :
494 : 0 : pthread_spin_lock(&ctx->ctrl_lock);
495 [ # # ]: 0 : LIST_INSERT_HEAD(&ctx->head, tbl, next);
496 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
497 : :
498 : 0 : return tbl;
499 : :
500 : : free_tbl:
501 : : simple_free(tbl);
502 : 0 : return NULL;
503 : : }
504 : :
505 : 0 : int mlx5dr_table_destroy(struct mlx5dr_table *tbl)
506 : : {
507 : 0 : struct mlx5dr_context *ctx = tbl->ctx;
508 : 0 : pthread_spin_lock(&ctx->ctrl_lock);
509 [ # # # # ]: 0 : if (!LIST_EMPTY(&tbl->head) || !LIST_EMPTY(&tbl->isolated_matchers)) {
510 : 0 : DR_LOG(ERR, "Cannot destroy table containing matchers");
511 : 0 : rte_errno = EBUSY;
512 : 0 : goto unlock_err;
513 : : }
514 : :
515 [ # # ]: 0 : if (!LIST_EMPTY(&tbl->default_miss.head)) {
516 : 0 : DR_LOG(ERR, "Cannot destroy table pointed by default miss");
517 : 0 : rte_errno = EBUSY;
518 : 0 : goto unlock_err;
519 : : }
520 : :
521 [ # # ]: 0 : LIST_REMOVE(tbl, next);
522 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
523 : 0 : mlx5dr_table_uninit(tbl);
524 : : simple_free(tbl);
525 : :
526 : 0 : return 0;
527 : :
528 : 0 : unlock_err:
529 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
530 : 0 : return -rte_errno;
531 : : }
532 : :
533 : : static struct mlx5dr_devx_obj *
534 : : mlx5dr_table_get_last_ft(struct mlx5dr_table *tbl)
535 : : {
536 : 0 : struct mlx5dr_devx_obj *last_ft = tbl->ft;
537 : : struct mlx5dr_matcher *matcher;
538 : :
539 [ # # ]: 0 : LIST_FOREACH(matcher, &tbl->head, next)
540 : 0 : last_ft = matcher->end_ft;
541 : :
542 : : return last_ft;
543 : : }
544 : :
545 : 0 : int mlx5dr_table_ft_set_default_next_ft(struct mlx5dr_table *tbl,
546 : : struct mlx5dr_devx_obj *ft_obj)
547 : : {
548 : 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
549 : : int ret;
550 : :
551 : : /* Due to FW limitation, resetting the flow table to default action will
552 : : * disconnect RTC when ignore_flow_level_rtc_valid is not supported.
553 : : */
554 [ # # ]: 0 : if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid)
555 : : return 0;
556 : :
557 [ # # ]: 0 : if (mlx5dr_table_is_fdb_any(tbl->type))
558 : 0 : return mlx5dr_table_connect_to_default_miss_tbl(tbl, ft_obj);
559 : :
560 : 0 : ft_attr.type = tbl->fw_ft_type;
561 : 0 : ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION;
562 : : ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_DEFAULT;
563 : :
564 : 0 : ret = mlx5dr_cmd_flow_table_modify(ft_obj, &ft_attr);
565 [ # # ]: 0 : if (ret) {
566 : 0 : DR_LOG(ERR, "Failed to set FT default miss action");
567 : 0 : return ret;
568 : : }
569 : :
570 : : return 0;
571 : : }
572 : :
573 : 0 : int mlx5dr_table_ft_set_next_rtc(struct mlx5dr_devx_obj *ft,
574 : : uint32_t fw_ft_type,
575 : : struct mlx5dr_devx_obj *rtc_0,
576 : : struct mlx5dr_devx_obj *rtc_1)
577 : : {
578 : 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
579 : :
580 : 0 : ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID;
581 : 0 : ft_attr.type = fw_ft_type;
582 [ # # ]: 0 : ft_attr.rtc_id_0 = rtc_0 ? rtc_0->id : 0;
583 [ # # ]: 0 : ft_attr.rtc_id_1 = rtc_1 ? rtc_1->id : 0;
584 : :
585 : 0 : return mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
586 : : }
587 : :
588 : : static int mlx5dr_table_ft_set_next_ft(struct mlx5dr_devx_obj *ft,
589 : : uint32_t fw_ft_type,
590 : : uint32_t next_ft_id)
591 : : {
592 : 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
593 : :
594 : 0 : ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION;
595 : 0 : ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL;
596 : 0 : ft_attr.type = fw_ft_type;
597 : 0 : ft_attr.table_miss_id = next_ft_id;
598 : :
599 : 0 : return mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
600 : : }
601 : :
602 : 0 : int mlx5dr_table_update_connected_miss_tables(struct mlx5dr_table *dst_tbl)
603 : : {
604 : : struct mlx5dr_table *src_tbl;
605 : : int ret;
606 : :
607 [ # # ]: 0 : if (LIST_EMPTY(&dst_tbl->default_miss.head))
608 : : return 0;
609 : :
610 [ # # ]: 0 : LIST_FOREACH(src_tbl, &dst_tbl->default_miss.head, default_miss.next) {
611 : 0 : ret = mlx5dr_table_connect_to_miss_table(src_tbl, dst_tbl, false);
612 [ # # ]: 0 : if (ret) {
613 : 0 : DR_LOG(ERR, "Failed to update source miss table, unexpected behavior");
614 : 0 : return ret;
615 : : }
616 : : }
617 : :
618 : : return 0;
619 : : }
620 : :
621 : 0 : int mlx5dr_table_connect_src_ft_to_miss_table(struct mlx5dr_table *src_tbl,
622 : : struct mlx5dr_devx_obj *ft,
623 : : struct mlx5dr_table *dst_tbl)
624 : : {
625 : : struct mlx5dr_matcher *matcher;
626 : : int ret;
627 : :
628 [ # # ]: 0 : if (dst_tbl) {
629 [ # # ]: 0 : if (LIST_EMPTY(&dst_tbl->head)) {
630 : : /* Connect src_tbl ft to dst_tbl start anchor */
631 : 0 : ret = mlx5dr_table_ft_set_next_ft(ft,
632 : : src_tbl->fw_ft_type,
633 : 0 : dst_tbl->ft->id);
634 [ # # ]: 0 : if (ret)
635 : : return ret;
636 : :
637 : : /* Reset ft RTC to default RTC */
638 : 0 : ret = mlx5dr_table_ft_set_next_rtc(ft,
639 : : src_tbl->fw_ft_type,
640 : : NULL, NULL);
641 [ # # ]: 0 : if (ret)
642 : 0 : return ret;
643 : : } else {
644 : : /* Connect src_tbl ft to first matcher RTC */
645 : : matcher = LIST_FIRST(&dst_tbl->head);
646 : 0 : ret = mlx5dr_table_ft_set_next_rtc(ft,
647 : : src_tbl->fw_ft_type,
648 : : matcher->match_ste.rtc_0,
649 : : matcher->match_ste.rtc_1);
650 [ # # ]: 0 : if (ret)
651 : : return ret;
652 : :
653 : : /* Reset next miss FT to default */
654 : 0 : ret = mlx5dr_table_ft_set_default_next_ft(src_tbl, ft);
655 [ # # ]: 0 : if (ret)
656 : 0 : return ret;
657 : : }
658 : : } else {
659 : : /* Reset next miss FT to default */
660 : 0 : ret = mlx5dr_table_ft_set_default_next_ft(src_tbl, ft);
661 [ # # ]: 0 : if (ret)
662 : : return ret;
663 : :
664 : : /* Reset ft RTC to default RTC */
665 : 0 : ret = mlx5dr_table_ft_set_next_rtc(ft,
666 : : src_tbl->fw_ft_type,
667 : : NULL, NULL);
668 [ # # ]: 0 : if (ret)
669 : 0 : return ret;
670 : : }
671 : :
672 : : return 0;
673 : : }
674 : :
675 : 0 : int mlx5dr_table_connect_to_miss_table(struct mlx5dr_table *src_tbl,
676 : : struct mlx5dr_table *dst_tbl,
677 : : bool only_update_last_ft)
678 : : {
679 : : struct mlx5dr_matcher *matcher;
680 : : struct mlx5dr_devx_obj *ft;
681 : : int ret;
682 : :
683 : : /* Connect last FT in the src_tbl matchers chain */
684 : : ft = mlx5dr_table_get_last_ft(src_tbl);
685 : 0 : ret = mlx5dr_table_connect_src_ft_to_miss_table(src_tbl, ft, dst_tbl);
686 [ # # ]: 0 : if (ret)
687 : : return ret;
688 : :
689 [ # # ]: 0 : if (!only_update_last_ft) {
690 : : /* Connect isolated matchers FT */
691 [ # # ]: 0 : LIST_FOREACH(matcher, &src_tbl->isolated_matchers, next) {
692 : 0 : ft = matcher->end_ft;
693 : 0 : ret = mlx5dr_table_connect_src_ft_to_miss_table(src_tbl, ft, dst_tbl);
694 [ # # ]: 0 : if (ret)
695 : 0 : return ret;
696 : : }
697 : : }
698 : :
699 : 0 : src_tbl->default_miss.miss_tbl = dst_tbl;
700 : :
701 : 0 : return 0;
702 : : }
703 : :
704 : : static bool mlx5dr_table_set_default_miss_valid_types(enum mlx5dr_table_type from,
705 : : enum mlx5dr_table_type to)
706 : : {
707 [ # # ]: 0 : if (from == to ||
708 : 0 : ((from == MLX5DR_TABLE_TYPE_FDB_UNIFIED &&
709 [ # # # # ]: 0 : (to == MLX5DR_TABLE_TYPE_FDB_RX || to == MLX5DR_TABLE_TYPE_FDB_TX)) ||
710 : 0 : (to == MLX5DR_TABLE_TYPE_FDB_UNIFIED &&
711 [ # # ]: 0 : (from == MLX5DR_TABLE_TYPE_FDB_RX || from == MLX5DR_TABLE_TYPE_FDB_TX))))
712 : : return true;
713 : :
714 : : return false;
715 : : }
716 : :
717 : 0 : static int mlx5dr_table_set_default_miss_not_valid(struct mlx5dr_table *tbl,
718 : : struct mlx5dr_table *miss_tbl)
719 : : {
720 [ # # # # ]: 0 : if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid ||
721 : : mlx5dr_context_shared_gvmi_used(tbl->ctx)) {
722 : 0 : DR_LOG(ERR, "Default miss table is not supported");
723 : 0 : rte_errno = EOPNOTSUPP;
724 : 0 : return -rte_errno;
725 : : }
726 : :
727 [ # # # # ]: 0 : if (mlx5dr_table_is_root(tbl) ||
728 [ # # ]: 0 : (miss_tbl &&
729 : : ((mlx5dr_table_is_root(miss_tbl)) ||
730 [ # # ]: 0 : !mlx5dr_table_set_default_miss_valid_types(tbl->type, miss_tbl->type)))) {
731 : 0 : DR_LOG(ERR, "Invalid arguments");
732 : 0 : rte_errno = EINVAL;
733 : 0 : return -rte_errno;
734 : : }
735 : :
736 : : return 0;
737 : : }
738 : :
739 : 0 : int mlx5dr_table_set_default_miss(struct mlx5dr_table *tbl,
740 : : struct mlx5dr_table *miss_tbl)
741 : : {
742 : 0 : struct mlx5dr_context *ctx = tbl->ctx;
743 : : struct mlx5dr_table *old_miss_tbl;
744 : : int ret;
745 : :
746 : 0 : ret = mlx5dr_table_set_default_miss_not_valid(tbl, miss_tbl);
747 [ # # ]: 0 : if (ret)
748 : : return ret;
749 : :
750 : 0 : pthread_spin_lock(&ctx->ctrl_lock);
751 : 0 : old_miss_tbl = tbl->default_miss.miss_tbl;
752 : 0 : ret = mlx5dr_table_connect_to_miss_table(tbl, miss_tbl, false);
753 [ # # ]: 0 : if (ret)
754 : 0 : goto out;
755 : :
756 [ # # ]: 0 : if (old_miss_tbl)
757 [ # # ]: 0 : LIST_REMOVE(tbl, default_miss.next);
758 : :
759 [ # # ]: 0 : if (miss_tbl)
760 [ # # ]: 0 : LIST_INSERT_HEAD(&miss_tbl->default_miss.head, tbl, default_miss.next);
761 : :
762 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
763 : 0 : return 0;
764 : : out:
765 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
766 : 0 : return -ret;
767 : : }
|