1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022 NVIDIA Corporation & Affiliates 3 */ 4 5 #include "mlx5dr_internal.h" 6 7 enum mlx5dr_matcher_rtc_type { 8 DR_MATCHER_RTC_TYPE_MATCH, 9 DR_MATCHER_RTC_TYPE_STE_ARRAY, 10 DR_MATCHER_RTC_TYPE_MAX, 11 }; 12 13 static const char * const mlx5dr_matcher_rtc_type_str[] = { 14 [DR_MATCHER_RTC_TYPE_MATCH] = "MATCH", 15 [DR_MATCHER_RTC_TYPE_STE_ARRAY] = "STE_ARRAY", 16 [DR_MATCHER_RTC_TYPE_MAX] = "UNKNOWN", 17 }; 18 19 static const char *mlx5dr_matcher_rtc_type_to_str(enum mlx5dr_matcher_rtc_type rtc_type) 20 { 21 if (rtc_type > DR_MATCHER_RTC_TYPE_MAX) 22 rtc_type = DR_MATCHER_RTC_TYPE_MAX; 23 return mlx5dr_matcher_rtc_type_str[rtc_type]; 24 } 25 26 static bool mlx5dr_matcher_requires_col_tbl(uint8_t log_num_of_rules) 27 { 28 /* Collision table concatenation is done only for large rule tables */ 29 return log_num_of_rules > MLX5DR_MATCHER_ASSURED_RULES_TH; 30 } 31 32 static uint8_t mlx5dr_matcher_rules_to_tbl_depth(uint8_t log_num_of_rules) 33 { 34 if (mlx5dr_matcher_requires_col_tbl(log_num_of_rules)) 35 return MLX5DR_MATCHER_ASSURED_MAIN_TBL_DEPTH; 36 37 /* For small rule tables we use a single deep table to assure insertion */ 38 return RTE_MIN(log_num_of_rules, MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH); 39 } 40 41 static void mlx5dr_matcher_destroy_end_ft(struct mlx5dr_matcher *matcher) 42 { 43 mlx5dr_table_destroy_default_ft(matcher->tbl, matcher->end_ft); 44 } 45 46 int mlx5dr_matcher_free_rtc_pointing(struct mlx5dr_context *ctx, 47 uint32_t fw_ft_type, 48 enum mlx5dr_table_type type, 49 struct mlx5dr_devx_obj *devx_obj) 50 { 51 int ret; 52 53 if (type != MLX5DR_TABLE_TYPE_FDB && !mlx5dr_context_shared_gvmi_used(ctx)) 54 return 0; 55 56 ret = mlx5dr_table_ft_set_next_rtc(devx_obj, fw_ft_type, NULL, NULL); 57 if (ret) 58 DR_LOG(ERR, "Failed to disconnect previous RTC"); 59 60 return ret; 61 } 62 63 static int mlx5dr_matcher_shared_point_end_ft(struct mlx5dr_matcher *matcher) 64 { 65 struct mlx5dr_cmd_ft_modify_attr ft_attr = {0}; 66 int ret; 67 68 mlx5dr_cmd_set_attr_connect_miss_tbl(matcher->tbl->ctx, 69 matcher->tbl->fw_ft_type, 70 matcher->tbl->type, 71 &ft_attr); 72 73 ret = mlx5dr_cmd_flow_table_modify(matcher->end_ft, &ft_attr); 74 if (ret) { 75 DR_LOG(ERR, "Failed to connect new matcher to default miss alias RTC"); 76 return ret; 77 } 78 79 ret = mlx5dr_matcher_free_rtc_pointing(matcher->tbl->ctx, 80 matcher->tbl->fw_ft_type, 81 matcher->tbl->type, 82 matcher->end_ft); 83 84 return ret; 85 } 86 87 static int mlx5dr_matcher_shared_create_alias_rtc(struct mlx5dr_matcher *matcher) 88 { 89 struct mlx5dr_context *ctx = matcher->tbl->ctx; 90 int ret; 91 92 ret = mlx5dr_matcher_create_aliased_obj(ctx, 93 ctx->ibv_ctx, 94 ctx->local_ibv_ctx, 95 ctx->caps->shared_vhca_id, 96 matcher->match_ste.rtc_0->id, 97 MLX5_GENERAL_OBJ_TYPE_RTC, 98 &matcher->match_ste.aliased_rtc_0); 99 if (ret) { 100 DR_LOG(ERR, "Failed to allocate alias RTC"); 101 return ret; 102 } 103 return 0; 104 } 105 106 static int mlx5dr_matcher_create_init_shared(struct mlx5dr_matcher *matcher) 107 { 108 if (!mlx5dr_context_shared_gvmi_used(matcher->tbl->ctx)) 109 return 0; 110 111 if (mlx5dr_matcher_shared_point_end_ft(matcher)) { 112 DR_LOG(ERR, "Failed to point shared matcher end flow table"); 113 return rte_errno; 114 } 115 116 if (mlx5dr_matcher_shared_create_alias_rtc(matcher)) { 117 DR_LOG(ERR, "Failed to create alias RTC"); 118 return rte_errno; 119 } 120 121 return 0; 122 } 123 124 static void mlx5dr_matcher_create_uninit_shared(struct mlx5dr_matcher *matcher) 125 { 126 if (!mlx5dr_context_shared_gvmi_used(matcher->tbl->ctx)) 127 return; 128 129 if (matcher->match_ste.aliased_rtc_0) { 130 mlx5dr_cmd_destroy_obj(matcher->match_ste.aliased_rtc_0); 131 matcher->match_ste.aliased_rtc_0 = NULL; 132 } 133 } 134 135 static int mlx5dr_matcher_create_end_ft(struct mlx5dr_matcher *matcher) 136 { 137 struct mlx5dr_table *tbl = matcher->tbl; 138 139 matcher->end_ft = mlx5dr_table_create_default_ft(tbl->ctx->ibv_ctx, tbl); 140 if (!matcher->end_ft) { 141 DR_LOG(ERR, "Failed to create matcher end flow table"); 142 return rte_errno; 143 } 144 return 0; 145 } 146 147 static uint32_t 148 mlx5dr_matcher_connect_get_rtc0(struct mlx5dr_matcher *matcher) 149 { 150 if (!matcher->match_ste.aliased_rtc_0) 151 return matcher->match_ste.rtc_0->id; 152 else 153 return matcher->match_ste.aliased_rtc_0->id; 154 } 155 156 /* The function updates tbl->local_ft to the first RTC or 0 if no more matchers */ 157 static int mlx5dr_matcher_shared_update_local_ft(struct mlx5dr_table *tbl) 158 { 159 struct mlx5dr_cmd_ft_modify_attr cur_ft_attr = {0}; 160 struct mlx5dr_matcher *first_matcher; 161 int ret; 162 163 if (!mlx5dr_context_shared_gvmi_used(tbl->ctx)) 164 return 0; 165 166 first_matcher = LIST_FIRST(&tbl->head); 167 if (!first_matcher) { 168 /* local ft no longer points to any RTC, drop refcount */ 169 ret = mlx5dr_matcher_free_rtc_pointing(tbl->ctx, 170 tbl->fw_ft_type, 171 tbl->type, 172 tbl->local_ft); 173 if (ret) 174 DR_LOG(ERR, "Failed to clear local FT to prev alias RTC"); 175 176 return ret; 177 } 178 179 /* point local_ft to the first RTC */ 180 cur_ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; 181 cur_ft_attr.type = tbl->fw_ft_type; 182 cur_ft_attr.rtc_id_0 = mlx5dr_matcher_connect_get_rtc0(first_matcher); 183 184 ret = mlx5dr_cmd_flow_table_modify(tbl->local_ft, &cur_ft_attr); 185 if (ret) { 186 DR_LOG(ERR, "Failed to point local FT to alias RTC"); 187 return ret; 188 } 189 190 return 0; 191 } 192 193 static int mlx5dr_matcher_connect(struct mlx5dr_matcher *matcher) 194 { 195 struct mlx5dr_table *tbl = matcher->tbl; 196 struct mlx5dr_matcher *prev = NULL; 197 struct mlx5dr_matcher *next = NULL; 198 struct mlx5dr_matcher *tmp_matcher; 199 int ret; 200 201 /* Find location in matcher list */ 202 if (LIST_EMPTY(&tbl->head)) { 203 LIST_INSERT_HEAD(&tbl->head, matcher, next); 204 goto connect; 205 } 206 207 LIST_FOREACH(tmp_matcher, &tbl->head, next) { 208 if (tmp_matcher->attr.priority > matcher->attr.priority) { 209 next = tmp_matcher; 210 break; 211 } 212 prev = tmp_matcher; 213 } 214 215 if (next) 216 LIST_INSERT_BEFORE(next, matcher, next); 217 else 218 LIST_INSERT_AFTER(prev, matcher, next); 219 220 connect: 221 if (next) { 222 /* Connect to next RTC */ 223 ret = mlx5dr_table_ft_set_next_rtc(matcher->end_ft, 224 tbl->fw_ft_type, 225 next->match_ste.rtc_0, 226 next->match_ste.rtc_1); 227 if (ret) { 228 DR_LOG(ERR, "Failed to connect new matcher to next RTC"); 229 goto remove_from_list; 230 } 231 } else { 232 /* Connect last matcher to next miss_tbl if exists */ 233 ret = mlx5dr_table_connect_to_miss_table(tbl, tbl->default_miss.miss_tbl); 234 if (ret) { 235 DR_LOG(ERR, "Failed connect new matcher to miss_tbl"); 236 goto remove_from_list; 237 } 238 } 239 240 /* Connect to previous FT */ 241 ret = mlx5dr_table_ft_set_next_rtc(prev ? prev->end_ft : tbl->ft, 242 tbl->fw_ft_type, 243 matcher->match_ste.rtc_0, 244 matcher->match_ste.rtc_1); 245 if (ret) { 246 DR_LOG(ERR, "Failed to connect new matcher to previous FT"); 247 goto remove_from_list; 248 } 249 250 ret = mlx5dr_matcher_shared_update_local_ft(tbl); 251 if (ret) { 252 DR_LOG(ERR, "Failed to update local_ft anchor in shared table"); 253 goto remove_from_list; 254 } 255 256 /* Reset next miss FT to default (drop refcount) */ 257 ret = mlx5dr_table_ft_set_default_next_ft(tbl, prev ? prev->end_ft : tbl->ft); 258 if (ret) { 259 DR_LOG(ERR, "Failed to reset matcher ft default miss"); 260 goto remove_from_list; 261 } 262 263 if (!prev) { 264 /* Update tables missing to current matcher in the table */ 265 ret = mlx5dr_table_update_connected_miss_tables(tbl); 266 if (ret) { 267 DR_LOG(ERR, "Fatal error, failed to update connected miss table"); 268 goto remove_from_list; 269 } 270 } 271 272 return 0; 273 274 remove_from_list: 275 LIST_REMOVE(matcher, next); 276 return ret; 277 } 278 279 static int mlx5dr_matcher_disconnect(struct mlx5dr_matcher *matcher) 280 { 281 struct mlx5dr_matcher *tmp_matcher, *prev_matcher; 282 struct mlx5dr_table *tbl = matcher->tbl; 283 struct mlx5dr_devx_obj *prev_ft; 284 struct mlx5dr_matcher *next; 285 int ret; 286 287 prev_ft = tbl->ft; 288 prev_matcher = LIST_FIRST(&tbl->head); 289 LIST_FOREACH(tmp_matcher, &tbl->head, next) { 290 if (tmp_matcher == matcher) 291 break; 292 293 prev_ft = tmp_matcher->end_ft; 294 prev_matcher = tmp_matcher; 295 } 296 297 next = matcher->next.le_next; 298 299 LIST_REMOVE(matcher, next); 300 301 if (next) { 302 /* Connect previous end FT to next RTC */ 303 ret = mlx5dr_table_ft_set_next_rtc(prev_ft, 304 tbl->fw_ft_type, 305 next->match_ste.rtc_0, 306 next->match_ste.rtc_1); 307 if (ret) { 308 DR_LOG(ERR, "Failed to disconnect matcher"); 309 goto matcher_reconnect; 310 } 311 } else { 312 ret = mlx5dr_table_connect_to_miss_table(tbl, tbl->default_miss.miss_tbl); 313 if (ret) { 314 DR_LOG(ERR, "Failed to disconnect last matcher"); 315 goto matcher_reconnect; 316 } 317 } 318 319 ret = mlx5dr_matcher_shared_update_local_ft(tbl); 320 if (ret) { 321 DR_LOG(ERR, "Failed to update local_ft in shared table"); 322 goto matcher_reconnect; 323 } 324 325 /* Removing first matcher, update connected miss tables if exists */ 326 if (prev_ft == tbl->ft) { 327 ret = mlx5dr_table_update_connected_miss_tables(tbl); 328 if (ret) { 329 DR_LOG(ERR, "Fatal error, failed to update connected miss table"); 330 goto matcher_reconnect; 331 } 332 } 333 334 ret = mlx5dr_table_ft_set_default_next_ft(tbl, prev_ft); 335 if (ret) { 336 DR_LOG(ERR, "Fatal error, failed to restore matcher ft default miss"); 337 goto matcher_reconnect; 338 } 339 340 return 0; 341 342 matcher_reconnect: 343 if (LIST_EMPTY(&tbl->head) || prev_matcher == matcher) 344 LIST_INSERT_HEAD(&matcher->tbl->head, matcher, next); 345 else 346 LIST_INSERT_AFTER(prev_matcher, matcher, next); 347 348 return ret; 349 } 350 351 static bool mlx5dr_matcher_supp_fw_wqe(struct mlx5dr_matcher *matcher) 352 { 353 struct mlx5dr_cmd_query_caps *caps = matcher->tbl->ctx->caps; 354 355 if (matcher->flags & MLX5DR_MATCHER_FLAGS_HASH_DEFINER) { 356 if (matcher->hash_definer->type == MLX5DR_DEFINER_TYPE_MATCH && 357 !IS_BIT_SET(caps->supp_ste_format_gen_wqe, MLX5_IFC_RTC_STE_FORMAT_8DW)) { 358 DR_LOG(ERR, "Gen WQE MATCH format not supported"); 359 return false; 360 } 361 362 if (matcher->hash_definer->type == MLX5DR_DEFINER_TYPE_JUMBO) { 363 DR_LOG(ERR, "Gen WQE JUMBO format not supported"); 364 return false; 365 } 366 } 367 368 if (matcher->attr.insert_mode != MLX5DR_MATCHER_INSERT_BY_HASH || 369 matcher->attr.distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 370 DR_LOG(ERR, "Gen WQE must be inserted and distribute by hash"); 371 return false; 372 } 373 374 if ((matcher->flags & MLX5DR_MATCHER_FLAGS_RANGE_DEFINER) && 375 !IS_BIT_SET(caps->supp_ste_format_gen_wqe, MLX5_IFC_RTC_STE_FORMAT_RANGE)) { 376 DR_LOG(INFO, "Extended match gen wqe RANGE format not supported"); 377 return false; 378 } 379 380 if (!(caps->supp_type_gen_wqe & MLX5_GENERATE_WQE_TYPE_FLOW_UPDATE)) { 381 DR_LOG(ERR, "Gen WQE command not supporting GTA"); 382 return false; 383 } 384 385 if (!caps->rtc_max_hash_def_gen_wqe) { 386 DR_LOG(ERR, "Hash definer not supported"); 387 return false; 388 } 389 390 return true; 391 } 392 393 static void mlx5dr_matcher_set_rtc_attr_sz(struct mlx5dr_matcher *matcher, 394 struct mlx5dr_cmd_rtc_create_attr *rtc_attr, 395 enum mlx5dr_matcher_rtc_type rtc_type, 396 bool is_mirror) 397 { 398 enum mlx5dr_matcher_flow_src flow_src = matcher->attr.optimize_flow_src; 399 bool is_match_rtc = rtc_type == DR_MATCHER_RTC_TYPE_MATCH; 400 struct mlx5dr_pool_chunk *ste = &matcher->action_ste.ste; 401 402 if ((flow_src == MLX5DR_MATCHER_FLOW_SRC_VPORT && !is_mirror) || 403 (flow_src == MLX5DR_MATCHER_FLOW_SRC_WIRE && is_mirror)) { 404 /* Optimize FDB RTC */ 405 rtc_attr->log_size = 0; 406 rtc_attr->log_depth = 0; 407 } else { 408 /* Keep original values */ 409 rtc_attr->log_size = is_match_rtc ? matcher->attr.table.sz_row_log : ste->order; 410 rtc_attr->log_depth = is_match_rtc ? matcher->attr.table.sz_col_log : 0; 411 } 412 } 413 414 int mlx5dr_matcher_create_aliased_obj(struct mlx5dr_context *ctx, 415 struct ibv_context *ibv_owner, 416 struct ibv_context *ibv_allowed, 417 uint16_t vhca_id_to_be_accessed, 418 uint32_t aliased_object_id, 419 uint16_t object_type, 420 struct mlx5dr_devx_obj **obj) 421 { 422 struct mlx5dr_cmd_allow_other_vhca_access_attr allow_attr = {0}; 423 struct mlx5dr_cmd_alias_obj_create_attr alias_attr = {0}; 424 char key[ACCESS_KEY_LEN]; 425 int ret; 426 int i; 427 428 if (!mlx5dr_context_shared_gvmi_used(ctx)) 429 return 0; 430 431 for (i = 0; i < ACCESS_KEY_LEN; i++) 432 key[i] = rte_rand() & 0xFF; 433 434 memcpy(allow_attr.access_key, key, ACCESS_KEY_LEN); 435 allow_attr.obj_type = object_type; 436 allow_attr.obj_id = aliased_object_id; 437 438 ret = mlx5dr_cmd_allow_other_vhca_access(ibv_owner, &allow_attr); 439 if (ret) { 440 DR_LOG(ERR, "Failed to allow RTC to be aliased"); 441 return ret; 442 } 443 444 memcpy(alias_attr.access_key, key, ACCESS_KEY_LEN); 445 alias_attr.obj_id = aliased_object_id; 446 alias_attr.obj_type = object_type; 447 alias_attr.vhca_id = vhca_id_to_be_accessed; 448 *obj = mlx5dr_cmd_alias_obj_create(ibv_allowed, &alias_attr); 449 if (!*obj) { 450 DR_LOG(ERR, "Failed to create alias object"); 451 return rte_errno; 452 } 453 454 return 0; 455 } 456 457 static int mlx5dr_matcher_create_rtc(struct mlx5dr_matcher *matcher, 458 enum mlx5dr_matcher_rtc_type rtc_type) 459 { 460 struct mlx5dr_matcher_attr *attr = &matcher->attr; 461 struct mlx5dr_cmd_rtc_create_attr rtc_attr = {0}; 462 struct mlx5dr_match_template *mt = matcher->mt; 463 struct mlx5dr_context *ctx = matcher->tbl->ctx; 464 struct mlx5dr_action_default_stc *default_stc; 465 struct mlx5dr_table *tbl = matcher->tbl; 466 struct mlx5dr_devx_obj **rtc_0, **rtc_1; 467 struct mlx5dr_pool *ste_pool, *stc_pool; 468 struct mlx5dr_devx_obj *devx_obj; 469 struct mlx5dr_pool_chunk *ste; 470 int ret; 471 472 switch (rtc_type) { 473 case DR_MATCHER_RTC_TYPE_MATCH: 474 rtc_0 = &matcher->match_ste.rtc_0; 475 rtc_1 = &matcher->match_ste.rtc_1; 476 ste_pool = matcher->match_ste.pool; 477 ste = &matcher->match_ste.ste; 478 ste->order = attr->table.sz_col_log + attr->table.sz_row_log; 479 480 /* Add additional rows due to additional range STE */ 481 if (mlx5dr_matcher_mt_is_range(mt)) 482 ste->order++; 483 484 rtc_attr.log_size = attr->table.sz_row_log; 485 rtc_attr.log_depth = attr->table.sz_col_log; 486 rtc_attr.is_frst_jumbo = mlx5dr_matcher_mt_is_jumbo(mt); 487 rtc_attr.is_scnd_range = mlx5dr_matcher_mt_is_range(mt); 488 rtc_attr.is_compare = mlx5dr_matcher_is_compare(matcher); 489 rtc_attr.miss_ft_id = matcher->end_ft->id; 490 491 if (attr->insert_mode == MLX5DR_MATCHER_INSERT_BY_HASH) { 492 /* The usual Hash Table */ 493 rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH; 494 495 if (matcher->hash_definer) { 496 /* Specify definer_id_0 is used for hashing */ 497 rtc_attr.fw_gen_wqe = true; 498 rtc_attr.num_hash_definer = 1; 499 rtc_attr.match_definer_0 = 500 mlx5dr_definer_get_id(matcher->hash_definer); 501 } else if (mlx5dr_matcher_is_compare(matcher)) { 502 rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer; 503 rtc_attr.fw_gen_wqe = true; 504 rtc_attr.num_hash_definer = 1; 505 } else { 506 /* The first mt is used since all share the same definer */ 507 rtc_attr.match_definer_0 = mlx5dr_definer_get_id(mt->definer); 508 509 /* This is tricky, instead of passing two definers for 510 * match and range, we specify that this RTC uses a hash 511 * definer, this will allow us to use any range definer 512 * since only first STE is used for hashing anyways. 513 */ 514 if (matcher->flags & MLX5DR_MATCHER_FLAGS_RANGE_DEFINER) { 515 rtc_attr.fw_gen_wqe = true; 516 rtc_attr.num_hash_definer = 1; 517 } 518 } 519 } else if (attr->insert_mode == MLX5DR_MATCHER_INSERT_BY_INDEX) { 520 rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; 521 rtc_attr.num_hash_definer = 1; 522 523 if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 524 /* Hash Split Table */ 525 rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH; 526 rtc_attr.match_definer_0 = mlx5dr_definer_get_id(mt->definer); 527 } else if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_LINEAR) { 528 /* Linear Lookup Table */ 529 rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR; 530 rtc_attr.match_definer_0 = ctx->caps->linear_match_definer; 531 } 532 } 533 534 /* Match pool requires implicit allocation */ 535 ret = mlx5dr_pool_chunk_alloc(ste_pool, ste); 536 if (ret) { 537 DR_LOG(ERR, "Failed to allocate STE for %s RTC", 538 mlx5dr_matcher_rtc_type_to_str(rtc_type)); 539 return ret; 540 } 541 break; 542 543 case DR_MATCHER_RTC_TYPE_STE_ARRAY: 544 rtc_0 = &matcher->action_ste.rtc_0; 545 rtc_1 = &matcher->action_ste.rtc_1; 546 ste_pool = matcher->action_ste.pool; 547 ste = &matcher->action_ste.ste; 548 ste->order = rte_log2_u32(matcher->action_ste.max_stes) + 549 attr->table.sz_row_log; 550 rtc_attr.log_size = ste->order; 551 rtc_attr.log_depth = 0; 552 rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; 553 /* The action STEs use the default always hit definer */ 554 rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer; 555 rtc_attr.is_frst_jumbo = false; 556 rtc_attr.miss_ft_id = 0; 557 break; 558 559 default: 560 DR_LOG(ERR, "HWS Invalid RTC type"); 561 rte_errno = EINVAL; 562 return rte_errno; 563 } 564 565 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(ste_pool, ste); 566 567 rtc_attr.pd = ctx->pd_num; 568 rtc_attr.ste_base = devx_obj->id; 569 rtc_attr.ste_offset = ste->offset; 570 rtc_attr.reparse_mode = mlx5dr_context_get_reparse_mode(ctx); 571 rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, false); 572 mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, false); 573 574 /* STC is a single resource (devx_obj), use any STC for the ID */ 575 stc_pool = ctx->stc_pool[tbl->type]; 576 default_stc = ctx->common_res[tbl->type].default_stc; 577 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, &default_stc->default_hit); 578 rtc_attr.stc_base = devx_obj->id; 579 580 *rtc_0 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr); 581 if (!*rtc_0) { 582 DR_LOG(ERR, "Failed to create matcher RTC of type %s", 583 mlx5dr_matcher_rtc_type_to_str(rtc_type)); 584 goto free_ste; 585 } 586 587 if (tbl->type == MLX5DR_TABLE_TYPE_FDB) { 588 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(ste_pool, ste); 589 rtc_attr.ste_base = devx_obj->id; 590 rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, true); 591 592 devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, &default_stc->default_hit); 593 rtc_attr.stc_base = devx_obj->id; 594 mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, true); 595 596 *rtc_1 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr); 597 if (!*rtc_1) { 598 DR_LOG(ERR, "Failed to create peer matcher RTC of type %s", 599 mlx5dr_matcher_rtc_type_to_str(rtc_type)); 600 goto destroy_rtc_0; 601 } 602 } 603 604 return 0; 605 606 destroy_rtc_0: 607 mlx5dr_cmd_destroy_obj(*rtc_0); 608 free_ste: 609 if (rtc_type == DR_MATCHER_RTC_TYPE_MATCH) 610 mlx5dr_pool_chunk_free(ste_pool, ste); 611 return rte_errno; 612 } 613 614 static void mlx5dr_matcher_destroy_rtc(struct mlx5dr_matcher *matcher, 615 enum mlx5dr_matcher_rtc_type rtc_type) 616 { 617 struct mlx5dr_table *tbl = matcher->tbl; 618 struct mlx5dr_devx_obj *rtc_0, *rtc_1; 619 struct mlx5dr_pool_chunk *ste; 620 struct mlx5dr_pool *ste_pool; 621 622 switch (rtc_type) { 623 case DR_MATCHER_RTC_TYPE_MATCH: 624 rtc_0 = matcher->match_ste.rtc_0; 625 rtc_1 = matcher->match_ste.rtc_1; 626 ste_pool = matcher->match_ste.pool; 627 ste = &matcher->match_ste.ste; 628 break; 629 case DR_MATCHER_RTC_TYPE_STE_ARRAY: 630 rtc_0 = matcher->action_ste.rtc_0; 631 rtc_1 = matcher->action_ste.rtc_1; 632 ste_pool = matcher->action_ste.pool; 633 ste = &matcher->action_ste.ste; 634 break; 635 default: 636 return; 637 } 638 639 if (tbl->type == MLX5DR_TABLE_TYPE_FDB) 640 mlx5dr_cmd_destroy_obj(rtc_1); 641 642 mlx5dr_cmd_destroy_obj(rtc_0); 643 if (rtc_type == DR_MATCHER_RTC_TYPE_MATCH) 644 mlx5dr_pool_chunk_free(ste_pool, ste); 645 } 646 647 static int 648 mlx5dr_matcher_check_attr_sz(struct mlx5dr_cmd_query_caps *caps, 649 struct mlx5dr_matcher_attr *attr) 650 { 651 if (attr->table.sz_col_log > caps->rtc_log_depth_max) { 652 DR_LOG(ERR, "Matcher depth exceeds limit %d", caps->rtc_log_depth_max); 653 goto not_supported; 654 } 655 656 if (attr->table.sz_col_log + attr->table.sz_row_log > caps->ste_alloc_log_max) { 657 DR_LOG(ERR, "Total matcher size exceeds limit %d", caps->ste_alloc_log_max); 658 goto not_supported; 659 } 660 661 if (attr->table.sz_col_log + attr->table.sz_row_log < caps->ste_alloc_log_gran) { 662 DR_LOG(ERR, "Total matcher size below limit %d", caps->ste_alloc_log_gran); 663 goto not_supported; 664 } 665 666 return 0; 667 668 not_supported: 669 rte_errno = EOPNOTSUPP; 670 return rte_errno; 671 } 672 673 static void mlx5dr_matcher_set_pool_attr(struct mlx5dr_pool_attr *attr, 674 struct mlx5dr_matcher *matcher) 675 { 676 switch (matcher->attr.optimize_flow_src) { 677 case MLX5DR_MATCHER_FLOW_SRC_VPORT: 678 attr->opt_type = MLX5DR_POOL_OPTIMIZE_ORIG; 679 break; 680 case MLX5DR_MATCHER_FLOW_SRC_WIRE: 681 attr->opt_type = MLX5DR_POOL_OPTIMIZE_MIRROR; 682 break; 683 default: 684 break; 685 } 686 } 687 688 static int mlx5dr_matcher_check_and_process_at(struct mlx5dr_matcher *matcher, 689 struct mlx5dr_action_template *at) 690 { 691 bool valid; 692 int ret; 693 694 if (!(at->flags & MLX5DR_ACTION_TEMPLATE_FLAG_RELAXED_ORDER)) { 695 /* Check if actions combinabtion is valid, 696 * in the case of not relaxed actions order. 697 */ 698 valid = mlx5dr_action_check_combo(at->action_type_arr, matcher->tbl->type); 699 if (!valid) { 700 DR_LOG(ERR, "Invalid combination in action template"); 701 rte_errno = EINVAL; 702 return rte_errno; 703 } 704 } 705 706 /* Process action template to setters */ 707 ret = mlx5dr_action_template_process(at); 708 if (ret) { 709 DR_LOG(ERR, "Failed to process action template"); 710 return ret; 711 } 712 713 return 0; 714 } 715 716 static int 717 mlx5dr_matcher_resize_init(struct mlx5dr_matcher *src_matcher) 718 { 719 struct mlx5dr_matcher_resize_data *resize_data; 720 721 resize_data = simple_calloc(1, sizeof(*resize_data)); 722 if (!resize_data) { 723 rte_errno = ENOMEM; 724 return rte_errno; 725 } 726 727 resize_data->max_stes = src_matcher->action_ste.max_stes; 728 resize_data->ste = src_matcher->action_ste.ste; 729 resize_data->stc = src_matcher->action_ste.stc; 730 resize_data->action_ste_rtc_0 = src_matcher->action_ste.rtc_0; 731 resize_data->action_ste_rtc_1 = src_matcher->action_ste.rtc_1; 732 resize_data->action_ste_pool = src_matcher->action_ste.max_stes ? 733 src_matcher->action_ste.pool : 734 NULL; 735 736 /* Place the new resized matcher on the dst matcher's list */ 737 LIST_INSERT_HEAD(&src_matcher->resize_dst->resize_data, 738 resize_data, next); 739 740 /* Move all the previous resized matchers to the dst matcher's list */ 741 while (!LIST_EMPTY(&src_matcher->resize_data)) { 742 resize_data = LIST_FIRST(&src_matcher->resize_data); 743 LIST_REMOVE(resize_data, next); 744 LIST_INSERT_HEAD(&src_matcher->resize_dst->resize_data, 745 resize_data, next); 746 } 747 748 return 0; 749 } 750 751 static void 752 mlx5dr_matcher_resize_uninit(struct mlx5dr_matcher *matcher) 753 { 754 struct mlx5dr_matcher_resize_data *resize_data; 755 756 if (!mlx5dr_matcher_is_resizable(matcher)) 757 return; 758 759 while (!LIST_EMPTY(&matcher->resize_data)) { 760 resize_data = LIST_FIRST(&matcher->resize_data); 761 LIST_REMOVE(resize_data, next); 762 763 if (resize_data->max_stes) { 764 mlx5dr_action_free_single_stc(matcher->tbl->ctx, 765 matcher->tbl->type, 766 &resize_data->stc); 767 768 if (matcher->tbl->type == MLX5DR_TABLE_TYPE_FDB) 769 mlx5dr_cmd_destroy_obj(resize_data->action_ste_rtc_1); 770 mlx5dr_cmd_destroy_obj(resize_data->action_ste_rtc_0); 771 if (resize_data->action_ste_pool) 772 mlx5dr_pool_destroy(resize_data->action_ste_pool); 773 } 774 775 simple_free(resize_data); 776 } 777 } 778 779 static int mlx5dr_matcher_bind_at(struct mlx5dr_matcher *matcher) 780 { 781 bool is_jumbo = mlx5dr_matcher_mt_is_jumbo(matcher->mt); 782 struct mlx5dr_cmd_stc_modify_attr stc_attr = {0}; 783 struct mlx5dr_table *tbl = matcher->tbl; 784 struct mlx5dr_pool_attr pool_attr = {0}; 785 struct mlx5dr_context *ctx = tbl->ctx; 786 uint32_t required_stes; 787 int i, ret; 788 789 if (matcher->flags & MLX5DR_MATCHER_FLAGS_COLLISION) 790 return 0; 791 792 if (matcher->attr.max_num_of_at_attach && 793 mlx5dr_matcher_req_fw_wqe(matcher)) { 794 DR_LOG(ERR, "FW extended matcher doesn't support additional at"); 795 rte_errno = ENOTSUP; 796 return rte_errno; 797 } 798 799 for (i = 0; i < matcher->num_of_at; i++) { 800 struct mlx5dr_action_template *at = &matcher->at[i]; 801 802 ret = mlx5dr_matcher_check_and_process_at(matcher, at); 803 if (ret) { 804 DR_LOG(ERR, "Invalid at %d", i); 805 return rte_errno; 806 } 807 808 required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term); 809 matcher->action_ste.max_stes = RTE_MAX(matcher->action_ste.max_stes, required_stes); 810 811 /* Future: Optimize reparse */ 812 } 813 814 /* There are no additioanl STEs required for matcher */ 815 if (!matcher->action_ste.max_stes) 816 return 0; 817 818 if (mlx5dr_matcher_req_fw_wqe(matcher)) { 819 DR_LOG(ERR, "FW extended matcher cannot be binded to complex at"); 820 rte_errno = ENOTSUP; 821 return rte_errno; 822 } 823 824 /* Allocate action STE mempool */ 825 pool_attr.table_type = tbl->type; 826 pool_attr.pool_type = MLX5DR_POOL_TYPE_STE; 827 pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_STE_ACTION_POOL; 828 pool_attr.alloc_log_sz = rte_log2_u32(matcher->action_ste.max_stes) + 829 matcher->attr.table.sz_row_log; 830 mlx5dr_matcher_set_pool_attr(&pool_attr, matcher); 831 matcher->action_ste.pool = mlx5dr_pool_create(ctx, &pool_attr); 832 if (!matcher->action_ste.pool) { 833 DR_LOG(ERR, "Failed to create action ste pool"); 834 return rte_errno; 835 } 836 837 /* Allocate action RTC */ 838 ret = mlx5dr_matcher_create_rtc(matcher, DR_MATCHER_RTC_TYPE_STE_ARRAY); 839 if (ret) { 840 DR_LOG(ERR, "Failed to create action RTC"); 841 goto free_ste_pool; 842 } 843 844 /* Allocate STC for jumps to STE */ 845 stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT; 846 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; 847 stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 848 stc_attr.ste_table.ste = matcher->action_ste.ste; 849 stc_attr.ste_table.ste_pool = matcher->action_ste.pool; 850 stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; 851 852 ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl->type, 853 &matcher->action_ste.stc); 854 if (ret) { 855 DR_LOG(ERR, "Failed to create action jump to table STC"); 856 goto free_rtc; 857 } 858 859 return 0; 860 861 free_rtc: 862 mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_STE_ARRAY); 863 free_ste_pool: 864 mlx5dr_pool_destroy(matcher->action_ste.pool); 865 return rte_errno; 866 } 867 868 static void mlx5dr_matcher_unbind_at(struct mlx5dr_matcher *matcher) 869 { 870 struct mlx5dr_table *tbl = matcher->tbl; 871 872 if (!matcher->action_ste.max_stes || 873 matcher->flags & MLX5DR_MATCHER_FLAGS_COLLISION || 874 mlx5dr_matcher_is_in_resize(matcher)) 875 return; 876 877 mlx5dr_action_free_single_stc(tbl->ctx, tbl->type, &matcher->action_ste.stc); 878 mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_STE_ARRAY); 879 mlx5dr_pool_destroy(matcher->action_ste.pool); 880 } 881 882 static int mlx5dr_matcher_bind_mt(struct mlx5dr_matcher *matcher) 883 { 884 struct mlx5dr_context *ctx = matcher->tbl->ctx; 885 struct mlx5dr_pool_attr pool_attr = {0}; 886 int ret; 887 888 /* Calculate match, range and hash definers */ 889 ret = mlx5dr_definer_matcher_init(ctx, matcher); 890 if (ret) { 891 DR_LOG(DEBUG, "Failed to set matcher templates with match definers"); 892 return ret; 893 } 894 895 if (mlx5dr_matcher_req_fw_wqe(matcher) && 896 !mlx5dr_matcher_supp_fw_wqe(matcher)) { 897 DR_LOG(ERR, "Matcher requires FW WQE which is not supported"); 898 rte_errno = ENOTSUP; 899 ret = rte_errno; 900 goto uninit_match_definer; 901 } 902 903 /* Create an STE pool per matcher*/ 904 pool_attr.table_type = matcher->tbl->type; 905 pool_attr.pool_type = MLX5DR_POOL_TYPE_STE; 906 pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_MATCHER_STE_POOL; 907 pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log + 908 matcher->attr.table.sz_row_log; 909 /* Add additional rows due to additional range STE */ 910 if (matcher->flags & MLX5DR_MATCHER_FLAGS_RANGE_DEFINER) 911 pool_attr.alloc_log_sz++; 912 mlx5dr_matcher_set_pool_attr(&pool_attr, matcher); 913 914 matcher->match_ste.pool = mlx5dr_pool_create(ctx, &pool_attr); 915 if (!matcher->match_ste.pool) { 916 DR_LOG(ERR, "Failed to allocate matcher STE pool"); 917 ret = ENOTSUP; 918 goto uninit_match_definer; 919 } 920 921 return 0; 922 923 uninit_match_definer: 924 mlx5dr_definer_matcher_uninit(matcher); 925 return ret; 926 } 927 928 static void mlx5dr_matcher_unbind_mt(struct mlx5dr_matcher *matcher) 929 { 930 mlx5dr_pool_destroy(matcher->match_ste.pool); 931 mlx5dr_definer_matcher_uninit(matcher); 932 } 933 934 static int 935 mlx5dr_matcher_validate_insert_mode(struct mlx5dr_cmd_query_caps *caps, 936 struct mlx5dr_matcher *matcher, 937 bool is_root) 938 { 939 struct mlx5dr_matcher_attr *attr = &matcher->attr; 940 941 if (is_root) { 942 if (attr->mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE) { 943 DR_LOG(ERR, "Root matcher supports only rule resource mode"); 944 goto not_supported; 945 } 946 if (attr->insert_mode != MLX5DR_MATCHER_INSERT_BY_HASH) { 947 DR_LOG(ERR, "Root matcher supports only insert by hash mode"); 948 goto not_supported; 949 } 950 if (attr->distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 951 DR_LOG(ERR, "Root matcher supports only distribute by hash mode"); 952 goto not_supported; 953 } 954 if (attr->optimize_flow_src) { 955 DR_LOG(ERR, "Root matcher can't specify FDB direction"); 956 goto not_supported; 957 } 958 } 959 960 switch (attr->insert_mode) { 961 case MLX5DR_MATCHER_INSERT_BY_HASH: 962 if (matcher->attr.distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 963 DR_LOG(ERR, "Invalid matcher distribute mode"); 964 goto not_supported; 965 } 966 break; 967 968 case MLX5DR_MATCHER_INSERT_BY_INDEX: 969 if (attr->table.sz_col_log) { 970 DR_LOG(ERR, "Matcher with INSERT_BY_INDEX supports only Nx1 table size"); 971 goto not_supported; 972 } 973 974 if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 975 /* Hash Split Table */ 976 if (!caps->rtc_hash_split_table) { 977 DR_LOG(ERR, "FW doesn't support insert by index and hash distribute"); 978 goto not_supported; 979 } 980 } else if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_LINEAR) { 981 /* Linear Lookup Table */ 982 if (!caps->rtc_linear_lookup_table || 983 !IS_BIT_SET(caps->access_index_mode, 984 MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR)) { 985 DR_LOG(ERR, "FW doesn't support insert by index and linear distribute"); 986 goto not_supported; 987 } 988 989 if (attr->table.sz_row_log > MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX) { 990 DR_LOG(ERR, "Matcher with linear distribute: rows exceed limit %d", 991 MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX); 992 goto not_supported; 993 } 994 } else { 995 DR_LOG(ERR, "Matcher has unsupported distribute mode"); 996 goto not_supported; 997 } 998 break; 999 1000 default: 1001 DR_LOG(ERR, "Matcher has unsupported insert mode"); 1002 goto not_supported; 1003 } 1004 1005 return 0; 1006 1007 not_supported: 1008 rte_errno = EOPNOTSUPP; 1009 return rte_errno; 1010 } 1011 1012 static int 1013 mlx5dr_matcher_process_attr(struct mlx5dr_cmd_query_caps *caps, 1014 struct mlx5dr_matcher *matcher, 1015 bool is_root) 1016 { 1017 struct mlx5dr_matcher_attr *attr = &matcher->attr; 1018 1019 if (mlx5dr_matcher_validate_insert_mode(caps, matcher, is_root)) 1020 goto not_supported; 1021 1022 if (is_root) { 1023 if (attr->optimize_flow_src) { 1024 DR_LOG(ERR, "Root matcher can't specify FDB direction"); 1025 goto not_supported; 1026 } 1027 if (attr->max_num_of_at_attach) { 1028 DR_LOG(ERR, "Root matcher does not support at attaching"); 1029 goto not_supported; 1030 } 1031 if (attr->resizable) { 1032 DR_LOG(ERR, "Root matcher does not support resizing"); 1033 goto not_supported; 1034 } 1035 return 0; 1036 } 1037 1038 if (matcher->tbl->type != MLX5DR_TABLE_TYPE_FDB && attr->optimize_flow_src) { 1039 DR_LOG(ERR, "NIC domain doesn't support flow_src"); 1040 goto not_supported; 1041 } 1042 1043 /* Convert number of rules to the required depth */ 1044 if (attr->mode == MLX5DR_MATCHER_RESOURCE_MODE_RULE && 1045 attr->insert_mode == MLX5DR_MATCHER_INSERT_BY_HASH) 1046 attr->table.sz_col_log = mlx5dr_matcher_rules_to_tbl_depth(attr->rule.num_log); 1047 1048 matcher->flags |= attr->resizable ? MLX5DR_MATCHER_FLAGS_RESIZABLE : 0; 1049 1050 return mlx5dr_matcher_check_attr_sz(caps, attr); 1051 1052 not_supported: 1053 rte_errno = EOPNOTSUPP; 1054 return rte_errno; 1055 } 1056 1057 static int mlx5dr_matcher_create_and_connect(struct mlx5dr_matcher *matcher) 1058 { 1059 int ret; 1060 1061 /* Select and create the definers for current matcher */ 1062 ret = mlx5dr_matcher_bind_mt(matcher); 1063 if (ret) 1064 return ret; 1065 1066 /* Calculate and verify action combination */ 1067 ret = mlx5dr_matcher_bind_at(matcher); 1068 if (ret) 1069 goto unbind_mt; 1070 1071 /* Create matcher end flow table anchor */ 1072 ret = mlx5dr_matcher_create_end_ft(matcher); 1073 if (ret) 1074 goto unbind_at; 1075 1076 /* Allocate the RTC for the new matcher */ 1077 ret = mlx5dr_matcher_create_rtc(matcher, DR_MATCHER_RTC_TYPE_MATCH); 1078 if (ret) 1079 goto destroy_end_ft; 1080 1081 /* Allocate and set shared resources */ 1082 ret = mlx5dr_matcher_create_init_shared(matcher); 1083 if (ret) 1084 goto destroy_rtc; 1085 1086 /* Connect the matcher to the matcher list */ 1087 ret = mlx5dr_matcher_connect(matcher); 1088 if (ret) 1089 goto destroy_shared; 1090 1091 return 0; 1092 1093 destroy_shared: 1094 mlx5dr_matcher_create_uninit_shared(matcher); 1095 destroy_rtc: 1096 mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_MATCH); 1097 destroy_end_ft: 1098 mlx5dr_matcher_destroy_end_ft(matcher); 1099 unbind_at: 1100 mlx5dr_matcher_unbind_at(matcher); 1101 unbind_mt: 1102 mlx5dr_matcher_unbind_mt(matcher); 1103 return ret; 1104 } 1105 1106 static void mlx5dr_matcher_destroy_and_disconnect(struct mlx5dr_matcher *matcher) 1107 { 1108 mlx5dr_matcher_resize_uninit(matcher); 1109 mlx5dr_matcher_disconnect(matcher); 1110 mlx5dr_matcher_create_uninit_shared(matcher); 1111 mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_MATCH); 1112 mlx5dr_matcher_destroy_end_ft(matcher); 1113 mlx5dr_matcher_unbind_at(matcher); 1114 mlx5dr_matcher_unbind_mt(matcher); 1115 } 1116 1117 static int 1118 mlx5dr_matcher_create_col_matcher(struct mlx5dr_matcher *matcher) 1119 { 1120 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1121 struct mlx5dr_matcher *col_matcher; 1122 int ret; 1123 1124 if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE || 1125 matcher->attr.insert_mode == MLX5DR_MATCHER_INSERT_BY_INDEX) 1126 return 0; 1127 1128 if (!mlx5dr_matcher_requires_col_tbl(matcher->attr.rule.num_log)) 1129 return 0; 1130 1131 col_matcher = simple_calloc(1, sizeof(*matcher)); 1132 if (!col_matcher) { 1133 rte_errno = ENOMEM; 1134 return rte_errno; 1135 } 1136 1137 col_matcher->tbl = matcher->tbl; 1138 col_matcher->mt = matcher->mt; 1139 col_matcher->at = matcher->at; 1140 col_matcher->num_of_at = matcher->num_of_at; 1141 col_matcher->num_of_mt = matcher->num_of_mt; 1142 col_matcher->hash_definer = matcher->hash_definer; 1143 col_matcher->attr.priority = matcher->attr.priority; 1144 col_matcher->flags = matcher->flags; 1145 col_matcher->flags |= MLX5DR_MATCHER_FLAGS_COLLISION; 1146 col_matcher->attr.mode = MLX5DR_MATCHER_RESOURCE_MODE_HTABLE; 1147 col_matcher->attr.optimize_flow_src = matcher->attr.optimize_flow_src; 1148 col_matcher->attr.table.sz_row_log = matcher->attr.rule.num_log; 1149 col_matcher->attr.table.sz_col_log = MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH; 1150 if (col_matcher->attr.table.sz_row_log > MLX5DR_MATCHER_ASSURED_ROW_RATIO) 1151 col_matcher->attr.table.sz_row_log -= MLX5DR_MATCHER_ASSURED_ROW_RATIO; 1152 1153 col_matcher->attr.max_num_of_at_attach = matcher->attr.max_num_of_at_attach; 1154 1155 ret = mlx5dr_matcher_process_attr(ctx->caps, col_matcher, false); 1156 if (ret) 1157 goto free_col_matcher; 1158 1159 ret = mlx5dr_matcher_create_and_connect(col_matcher); 1160 if (ret) 1161 goto free_col_matcher; 1162 1163 matcher->col_matcher = col_matcher; 1164 1165 return 0; 1166 1167 free_col_matcher: 1168 simple_free(col_matcher); 1169 DR_LOG(ERR, "Failed to create assured collision matcher"); 1170 return ret; 1171 } 1172 1173 static void 1174 mlx5dr_matcher_destroy_col_matcher(struct mlx5dr_matcher *matcher) 1175 { 1176 if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE || 1177 matcher->attr.insert_mode == MLX5DR_MATCHER_INSERT_BY_INDEX) 1178 return; 1179 1180 if (matcher->col_matcher) { 1181 mlx5dr_matcher_destroy_and_disconnect(matcher->col_matcher); 1182 simple_free(matcher->col_matcher); 1183 } 1184 } 1185 1186 static int mlx5dr_matcher_init(struct mlx5dr_matcher *matcher) 1187 { 1188 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1189 int ret; 1190 1191 pthread_spin_lock(&ctx->ctrl_lock); 1192 1193 /* Allocate matcher resource and connect to the packet pipe */ 1194 ret = mlx5dr_matcher_create_and_connect(matcher); 1195 if (ret) 1196 goto unlock_err; 1197 1198 /* Create additional matcher for collision handling */ 1199 ret = mlx5dr_matcher_create_col_matcher(matcher); 1200 if (ret) 1201 goto destory_and_disconnect; 1202 1203 pthread_spin_unlock(&ctx->ctrl_lock); 1204 1205 return 0; 1206 1207 destory_and_disconnect: 1208 mlx5dr_matcher_destroy_and_disconnect(matcher); 1209 unlock_err: 1210 pthread_spin_unlock(&ctx->ctrl_lock); 1211 return ret; 1212 } 1213 1214 static int mlx5dr_matcher_uninit(struct mlx5dr_matcher *matcher) 1215 { 1216 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1217 1218 pthread_spin_lock(&ctx->ctrl_lock); 1219 mlx5dr_matcher_destroy_col_matcher(matcher); 1220 mlx5dr_matcher_destroy_and_disconnect(matcher); 1221 pthread_spin_unlock(&ctx->ctrl_lock); 1222 1223 return 0; 1224 } 1225 1226 static int mlx5dr_matcher_init_root(struct mlx5dr_matcher *matcher) 1227 { 1228 enum mlx5dr_table_type type = matcher->tbl->type; 1229 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1230 struct mlx5dv_flow_matcher_attr attr = {0}; 1231 struct mlx5dv_flow_match_parameters *mask; 1232 struct mlx5_flow_attr flow_attr = {0}; 1233 struct rte_flow_error rte_error; 1234 uint8_t match_criteria; 1235 int ret; 1236 1237 #ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE 1238 attr.comp_mask = MLX5DV_FLOW_MATCHER_MASK_FT_TYPE; 1239 1240 switch (type) { 1241 case MLX5DR_TABLE_TYPE_NIC_RX: 1242 attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX; 1243 break; 1244 case MLX5DR_TABLE_TYPE_NIC_TX: 1245 attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX; 1246 break; 1247 case MLX5DR_TABLE_TYPE_FDB: 1248 attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB; 1249 break; 1250 default: 1251 assert(0); 1252 break; 1253 } 1254 #endif 1255 1256 if (matcher->attr.priority > UINT16_MAX) { 1257 DR_LOG(ERR, "Root matcher priority exceeds allowed limit"); 1258 rte_errno = EINVAL; 1259 return rte_errno; 1260 } 1261 1262 ret = flow_hw_get_port_id_from_ctx(ctx, &flow_attr.port_id); 1263 if (ret) { 1264 DR_LOG(ERR, "Failed to get port id for dev %s", ctx->ibv_ctx->device->name); 1265 rte_errno = EINVAL; 1266 return rte_errno; 1267 } 1268 1269 mask = simple_calloc(1, MLX5_ST_SZ_BYTES(fte_match_param) + 1270 offsetof(struct mlx5dv_flow_match_parameters, match_buf)); 1271 if (!mask) { 1272 rte_errno = ENOMEM; 1273 return rte_errno; 1274 } 1275 1276 flow_attr.tbl_type = type; 1277 1278 /* On root table matcher, only a single match template is supported */ 1279 ret = flow_dv_translate_items_hws(matcher->mt[0].items, 1280 &flow_attr, mask->match_buf, 1281 MLX5_SET_MATCHER_HS_M, NULL, 1282 &match_criteria, 1283 &rte_error); 1284 if (ret) { 1285 DR_LOG(ERR, "Failed to convert items to PRM [%s]", rte_error.message); 1286 goto free_mask; 1287 } 1288 1289 mask->match_sz = MLX5_ST_SZ_BYTES(fte_match_param); 1290 attr.match_mask = mask; 1291 attr.match_criteria_enable = match_criteria; 1292 attr.type = IBV_FLOW_ATTR_NORMAL; 1293 attr.priority = matcher->attr.priority; 1294 1295 matcher->dv_matcher = 1296 mlx5_glue->dv_create_flow_matcher_root(mlx5dr_context_get_local_ibv(ctx), 1297 &attr); 1298 if (!matcher->dv_matcher) { 1299 DR_LOG(ERR, "Failed to create DV flow matcher"); 1300 rte_errno = errno; 1301 goto free_mask; 1302 } 1303 1304 simple_free(mask); 1305 1306 pthread_spin_lock(&ctx->ctrl_lock); 1307 LIST_INSERT_HEAD(&matcher->tbl->head, matcher, next); 1308 pthread_spin_unlock(&ctx->ctrl_lock); 1309 1310 return 0; 1311 1312 free_mask: 1313 simple_free(mask); 1314 return rte_errno; 1315 } 1316 1317 static int mlx5dr_matcher_uninit_root(struct mlx5dr_matcher *matcher) 1318 { 1319 struct mlx5dr_context *ctx = matcher->tbl->ctx; 1320 int ret; 1321 1322 pthread_spin_lock(&ctx->ctrl_lock); 1323 LIST_REMOVE(matcher, next); 1324 pthread_spin_unlock(&ctx->ctrl_lock); 1325 1326 ret = mlx5_glue->dv_destroy_flow_matcher_root(matcher->dv_matcher); 1327 if (ret) { 1328 DR_LOG(ERR, "Failed to Destroy DV flow matcher"); 1329 rte_errno = errno; 1330 } 1331 1332 return ret; 1333 } 1334 1335 int mlx5dr_matcher_attach_at(struct mlx5dr_matcher *matcher, 1336 struct mlx5dr_action_template *at) 1337 { 1338 bool is_jumbo = mlx5dr_matcher_mt_is_jumbo(matcher->mt); 1339 uint32_t required_stes; 1340 int ret; 1341 1342 if (!matcher->attr.max_num_of_at_attach) { 1343 DR_LOG(DEBUG, "Num of current at (%d) exceed allowed value", 1344 matcher->num_of_at); 1345 rte_errno = ENOTSUP; 1346 return -rte_errno; 1347 } 1348 1349 ret = mlx5dr_matcher_check_and_process_at(matcher, at); 1350 if (ret) 1351 return -rte_errno; 1352 1353 required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term); 1354 if (matcher->action_ste.max_stes < required_stes) { 1355 DR_LOG(DEBUG, "Required STEs [%d] exceeds initial action template STE [%d]", 1356 required_stes, matcher->action_ste.max_stes); 1357 rte_errno = ENOMEM; 1358 return -rte_errno; 1359 } 1360 1361 matcher->at[matcher->num_of_at] = *at; 1362 matcher->num_of_at += 1; 1363 matcher->attr.max_num_of_at_attach -= 1; 1364 1365 if (matcher->col_matcher) 1366 matcher->col_matcher->num_of_at = matcher->num_of_at; 1367 1368 return 0; 1369 } 1370 1371 static int 1372 mlx5dr_matcher_set_templates(struct mlx5dr_matcher *matcher, 1373 struct mlx5dr_match_template *mt[], 1374 uint8_t num_of_mt, 1375 struct mlx5dr_action_template *at[], 1376 uint8_t num_of_at) 1377 { 1378 bool is_root = mlx5dr_table_is_root(matcher->tbl); 1379 int i; 1380 1381 if (!num_of_mt || !num_of_at) { 1382 DR_LOG(ERR, "Number of action/match template cannot be zero"); 1383 rte_errno = ENOTSUP; 1384 return rte_errno; 1385 } 1386 1387 if (is_root && num_of_mt > MLX5DR_MATCHER_MAX_MT_ROOT) { 1388 DR_LOG(ERR, "Number of match templates exceeds limit"); 1389 rte_errno = ENOTSUP; 1390 return rte_errno; 1391 } 1392 1393 matcher->mt = simple_calloc(num_of_mt, sizeof(*matcher->mt)); 1394 if (!matcher->mt) { 1395 DR_LOG(ERR, "Failed to allocate match template array"); 1396 rte_errno = ENOMEM; 1397 return rte_errno; 1398 } 1399 1400 matcher->at = simple_calloc(num_of_at + matcher->attr.max_num_of_at_attach, 1401 sizeof(*matcher->at)); 1402 if (!matcher->at) { 1403 DR_LOG(ERR, "Failed to allocate action template array"); 1404 rte_errno = ENOMEM; 1405 goto free_mt; 1406 } 1407 1408 for (i = 0; i < num_of_mt; i++) 1409 matcher->mt[i] = *mt[i]; 1410 1411 for (i = 0; i < num_of_at; i++) 1412 matcher->at[i] = *at[i]; 1413 1414 matcher->num_of_mt = num_of_mt; 1415 matcher->num_of_at = num_of_at; 1416 1417 return 0; 1418 1419 free_mt: 1420 simple_free(matcher->mt); 1421 return rte_errno; 1422 } 1423 1424 static void 1425 mlx5dr_matcher_unset_templates(struct mlx5dr_matcher *matcher) 1426 { 1427 simple_free(matcher->at); 1428 simple_free(matcher->mt); 1429 } 1430 1431 struct mlx5dr_matcher * 1432 mlx5dr_matcher_create(struct mlx5dr_table *tbl, 1433 struct mlx5dr_match_template *mt[], 1434 uint8_t num_of_mt, 1435 struct mlx5dr_action_template *at[], 1436 uint8_t num_of_at, 1437 struct mlx5dr_matcher_attr *attr) 1438 { 1439 bool is_root = mlx5dr_table_is_root(tbl); 1440 struct mlx5dr_matcher *matcher; 1441 int ret; 1442 1443 matcher = simple_calloc(1, sizeof(*matcher)); 1444 if (!matcher) { 1445 rte_errno = ENOMEM; 1446 return NULL; 1447 } 1448 1449 matcher->tbl = tbl; 1450 matcher->attr = *attr; 1451 1452 ret = mlx5dr_matcher_process_attr(tbl->ctx->caps, matcher, is_root); 1453 if (ret) 1454 goto free_matcher; 1455 1456 ret = mlx5dr_matcher_set_templates(matcher, mt, num_of_mt, at, num_of_at); 1457 if (ret) 1458 goto free_matcher; 1459 1460 if (is_root) 1461 ret = mlx5dr_matcher_init_root(matcher); 1462 else 1463 ret = mlx5dr_matcher_init(matcher); 1464 1465 if (ret) { 1466 DR_LOG(ERR, "Failed to initialise matcher: %d", ret); 1467 goto unset_templates; 1468 } 1469 1470 return matcher; 1471 1472 unset_templates: 1473 mlx5dr_matcher_unset_templates(matcher); 1474 free_matcher: 1475 simple_free(matcher); 1476 return NULL; 1477 } 1478 1479 int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher) 1480 { 1481 if (mlx5dr_table_is_root(matcher->tbl)) 1482 mlx5dr_matcher_uninit_root(matcher); 1483 else 1484 mlx5dr_matcher_uninit(matcher); 1485 1486 mlx5dr_matcher_unset_templates(matcher); 1487 simple_free(matcher); 1488 return 0; 1489 } 1490 1491 struct mlx5dr_match_template * 1492 mlx5dr_match_template_create(const struct rte_flow_item items[], 1493 enum mlx5dr_match_template_flags flags) 1494 { 1495 struct mlx5dr_match_template *mt; 1496 struct rte_flow_error error; 1497 int ret, len; 1498 1499 if (flags > MLX5DR_MATCH_TEMPLATE_FLAG_RELAXED_MATCH) { 1500 DR_LOG(ERR, "Unsupported match template flag provided"); 1501 rte_errno = EINVAL; 1502 return NULL; 1503 } 1504 1505 mt = simple_calloc(1, sizeof(*mt)); 1506 if (!mt) { 1507 DR_LOG(ERR, "Failed to allocate match template"); 1508 rte_errno = ENOMEM; 1509 return NULL; 1510 } 1511 1512 mt->flags = flags; 1513 1514 /* Duplicate the user given items */ 1515 ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, NULL, 0, items, &error); 1516 if (ret <= 0) { 1517 DR_LOG(ERR, "Unable to process items (%s): %s", 1518 error.message ? error.message : "unspecified", 1519 strerror(rte_errno)); 1520 goto free_template; 1521 } 1522 1523 len = RTE_ALIGN(ret, 16); 1524 mt->items = simple_calloc(1, len); 1525 if (!mt->items) { 1526 DR_LOG(ERR, "Failed to allocate item copy"); 1527 rte_errno = ENOMEM; 1528 goto free_template; 1529 } 1530 1531 ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, mt->items, ret, items, &error); 1532 if (ret <= 0) 1533 goto free_dst; 1534 1535 return mt; 1536 1537 free_dst: 1538 simple_free(mt->items); 1539 free_template: 1540 simple_free(mt); 1541 return NULL; 1542 } 1543 1544 int mlx5dr_match_template_destroy(struct mlx5dr_match_template *mt) 1545 { 1546 simple_free(mt->items); 1547 simple_free(mt); 1548 return 0; 1549 } 1550 1551 bool mlx5dr_matcher_is_updatable(struct mlx5dr_matcher *matcher) 1552 { 1553 if (mlx5dr_table_is_root(matcher->tbl) || 1554 mlx5dr_matcher_req_fw_wqe(matcher) || 1555 mlx5dr_matcher_is_resizable(matcher) || 1556 (!matcher->attr.optimize_using_rule_idx && 1557 !mlx5dr_matcher_is_insert_by_idx(matcher))) 1558 return false; 1559 1560 return true; 1561 } 1562 1563 bool mlx5dr_matcher_is_dependent(struct mlx5dr_matcher *matcher) 1564 { 1565 int i; 1566 1567 if (matcher->action_ste.max_stes || mlx5dr_matcher_req_fw_wqe(matcher)) 1568 return true; 1569 1570 for (i = 0; i < matcher->num_of_at; i++) { 1571 struct mlx5dr_action_template *at = &matcher->at[i]; 1572 1573 if (at->need_dep_write) 1574 return true; 1575 } 1576 1577 return false; 1578 } 1579 1580 static int mlx5dr_matcher_resize_precheck(struct mlx5dr_matcher *src_matcher, 1581 struct mlx5dr_matcher *dst_matcher) 1582 { 1583 int i; 1584 1585 if (mlx5dr_table_is_root(src_matcher->tbl) || 1586 mlx5dr_table_is_root(dst_matcher->tbl)) { 1587 DR_LOG(ERR, "Src/dst matcher belongs to root table - resize unsupported"); 1588 goto out_einval; 1589 } 1590 1591 if (src_matcher->tbl->type != dst_matcher->tbl->type) { 1592 DR_LOG(ERR, "Table type mismatch for src/dst matchers"); 1593 goto out_einval; 1594 } 1595 1596 if (mlx5dr_matcher_req_fw_wqe(src_matcher) || 1597 mlx5dr_matcher_req_fw_wqe(dst_matcher)) { 1598 DR_LOG(ERR, "Matchers require FW WQE - resize unsupported"); 1599 goto out_einval; 1600 } 1601 1602 if (!mlx5dr_matcher_is_resizable(src_matcher) || 1603 !mlx5dr_matcher_is_resizable(dst_matcher)) { 1604 DR_LOG(ERR, "Src/dst matcher is not resizable"); 1605 goto out_einval; 1606 } 1607 1608 if (mlx5dr_matcher_is_insert_by_idx(src_matcher) != 1609 mlx5dr_matcher_is_insert_by_idx(dst_matcher)) { 1610 DR_LOG(ERR, "Src/dst matchers insert mode mismatch"); 1611 goto out_einval; 1612 } 1613 1614 if (mlx5dr_matcher_is_in_resize(src_matcher) || 1615 mlx5dr_matcher_is_in_resize(dst_matcher)) { 1616 DR_LOG(ERR, "Src/dst matcher is already in resize"); 1617 goto out_einval; 1618 } 1619 1620 /* Compare match templates - make sure the definers are equivalent */ 1621 if (src_matcher->num_of_mt != dst_matcher->num_of_mt) { 1622 DR_LOG(ERR, "Src/dst matcher match templates mismatch"); 1623 goto out_einval; 1624 } 1625 1626 if (src_matcher->action_ste.max_stes > dst_matcher->action_ste.max_stes) { 1627 DR_LOG(ERR, "Src/dst matcher max STEs mismatch"); 1628 goto out_einval; 1629 } 1630 1631 for (i = 0; i < src_matcher->num_of_mt; i++) { 1632 if (mlx5dr_definer_compare(src_matcher->mt[i].definer, 1633 dst_matcher->mt[i].definer)) { 1634 DR_LOG(ERR, "Src/dst matcher definers mismatch"); 1635 goto out_einval; 1636 } 1637 } 1638 1639 return 0; 1640 1641 out_einval: 1642 rte_errno = EINVAL; 1643 return rte_errno; 1644 } 1645 1646 int mlx5dr_matcher_resize_set_target(struct mlx5dr_matcher *src_matcher, 1647 struct mlx5dr_matcher *dst_matcher) 1648 { 1649 int ret = 0; 1650 1651 pthread_spin_lock(&src_matcher->tbl->ctx->ctrl_lock); 1652 1653 if (mlx5dr_matcher_resize_precheck(src_matcher, dst_matcher)) { 1654 ret = -rte_errno; 1655 goto out; 1656 } 1657 1658 src_matcher->resize_dst = dst_matcher; 1659 1660 if (mlx5dr_matcher_resize_init(src_matcher)) { 1661 src_matcher->resize_dst = NULL; 1662 ret = -rte_errno; 1663 } 1664 1665 out: 1666 pthread_spin_unlock(&src_matcher->tbl->ctx->ctrl_lock); 1667 return ret; 1668 } 1669 1670 int mlx5dr_matcher_resize_rule_move(struct mlx5dr_matcher *src_matcher, 1671 struct mlx5dr_rule *rule, 1672 struct mlx5dr_rule_attr *attr) 1673 { 1674 if (unlikely(!mlx5dr_matcher_is_in_resize(src_matcher))) { 1675 DR_LOG(ERR, "Matcher is not resizable or not in resize"); 1676 goto out_einval; 1677 } 1678 1679 if (unlikely(src_matcher != rule->matcher)) { 1680 DR_LOG(ERR, "Rule doesn't belong to src matcher"); 1681 goto out_einval; 1682 } 1683 1684 return mlx5dr_rule_move_hws_add(rule, attr); 1685 1686 out_einval: 1687 rte_errno = EINVAL; 1688 return -rte_errno; 1689 } 1690 1691 int mlx5dr_matcher_validate_compare_attr(struct mlx5dr_matcher *matcher) 1692 { 1693 struct mlx5dr_cmd_query_caps *caps = matcher->tbl->ctx->caps; 1694 struct mlx5dr_matcher_attr *attr = &matcher->attr; 1695 1696 if (mlx5dr_table_is_root(matcher->tbl)) { 1697 DR_LOG(ERR, "Compare matcher is not supported for root tables"); 1698 goto err; 1699 } 1700 1701 if (attr->mode != MLX5DR_MATCHER_RESOURCE_MODE_HTABLE) { 1702 DR_LOG(ERR, "Compare matcher is only supported with pre-defined table size"); 1703 goto err; 1704 } 1705 1706 if (attr->insert_mode != MLX5DR_MATCHER_INSERT_BY_HASH || 1707 attr->distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) { 1708 DR_LOG(ERR, "Gen WQE for compare matcher must be inserted and distribute by hash"); 1709 goto err; 1710 } 1711 1712 if (matcher->num_of_mt != 1 || matcher->num_of_at != 1) { 1713 DR_LOG(ERR, "Compare matcher match templates and action templates must be 1 for each"); 1714 goto err; 1715 } 1716 1717 if (attr->table.sz_col_log || attr->table.sz_row_log) { 1718 DR_LOG(ERR, "Compare matcher supports only 1x1 table size"); 1719 goto err; 1720 } 1721 1722 if (attr->resizable) { 1723 DR_LOG(ERR, "Compare matcher does not support resizeing"); 1724 goto err; 1725 } 1726 1727 if (!IS_BIT_SET(caps->supp_ste_format_gen_wqe, MLX5_IFC_RTC_STE_FORMAT_4DW_RANGE)) { 1728 DR_LOG(ERR, "Gen WQE Compare match format not supported"); 1729 goto err; 1730 } 1731 1732 return 0; 1733 1734 err: 1735 rte_errno = ENOTSUP; 1736 return rte_errno; 1737 } 1738