1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2019 Mellanox Technologies. */ 3 4 #include "dr_types.h" 5 6 static bool dr_mask_is_smac_set(struct mlx5dr_match_spec *spec) 7 { 8 return (spec->smac_47_16 || spec->smac_15_0); 9 } 10 11 static bool dr_mask_is_dmac_set(struct mlx5dr_match_spec *spec) 12 { 13 return (spec->dmac_47_16 || spec->dmac_15_0); 14 } 15 16 static bool dr_mask_is_l3_base_set(struct mlx5dr_match_spec *spec) 17 { 18 return (spec->ip_protocol || spec->frag || spec->tcp_flags || 19 spec->ip_ecn || spec->ip_dscp); 20 } 21 22 static bool dr_mask_is_tcp_udp_base_set(struct mlx5dr_match_spec *spec) 23 { 24 return (spec->tcp_sport || spec->tcp_dport || 25 spec->udp_sport || spec->udp_dport); 26 } 27 28 static bool dr_mask_is_ipv4_set(struct mlx5dr_match_spec *spec) 29 { 30 return (spec->dst_ip_31_0 || spec->src_ip_31_0); 31 } 32 33 static bool dr_mask_is_ipv4_5_tuple_set(struct mlx5dr_match_spec *spec) 34 { 35 return (dr_mask_is_l3_base_set(spec) || 36 dr_mask_is_tcp_udp_base_set(spec) || 37 dr_mask_is_ipv4_set(spec)); 38 } 39 40 static bool dr_mask_is_eth_l2_tnl_set(struct mlx5dr_match_misc *misc) 41 { 42 return misc->vxlan_vni; 43 } 44 45 static bool dr_mask_is_ttl_set(struct mlx5dr_match_spec *spec) 46 { 47 return spec->ttl_hoplimit; 48 } 49 50 static bool dr_mask_is_ipv4_ihl_set(struct mlx5dr_match_spec *spec) 51 { 52 return spec->ipv4_ihl; 53 } 54 55 #define DR_MASK_IS_L2_DST(_spec, _misc, _inner_outer) (_spec.first_vid || \ 56 (_spec).first_cfi || (_spec).first_prio || (_spec).cvlan_tag || \ 57 (_spec).svlan_tag || (_spec).dmac_47_16 || (_spec).dmac_15_0 || \ 58 (_spec).ethertype || (_spec).ip_version || \ 59 (_misc)._inner_outer##_second_vid || \ 60 (_misc)._inner_outer##_second_cfi || \ 61 (_misc)._inner_outer##_second_prio || \ 62 (_misc)._inner_outer##_second_cvlan_tag || \ 63 (_misc)._inner_outer##_second_svlan_tag) 64 65 #define DR_MASK_IS_ETH_L4_SET(_spec, _misc, _inner_outer) ( \ 66 dr_mask_is_l3_base_set(&(_spec)) || \ 67 dr_mask_is_tcp_udp_base_set(&(_spec)) || \ 68 dr_mask_is_ttl_set(&(_spec)) || \ 69 (_misc)._inner_outer##_ipv6_flow_label) 70 71 #define DR_MASK_IS_ETH_L4_MISC_SET(_misc3, _inner_outer) ( \ 72 (_misc3)._inner_outer##_tcp_seq_num || \ 73 (_misc3)._inner_outer##_tcp_ack_num) 74 75 #define DR_MASK_IS_FIRST_MPLS_SET(_misc2, _inner_outer) ( \ 76 (_misc2)._inner_outer##_first_mpls_label || \ 77 (_misc2)._inner_outer##_first_mpls_exp || \ 78 (_misc2)._inner_outer##_first_mpls_s_bos || \ 79 (_misc2)._inner_outer##_first_mpls_ttl) 80 81 static bool dr_mask_is_tnl_gre_set(struct mlx5dr_match_misc *misc) 82 { 83 return (misc->gre_key_h || misc->gre_key_l || 84 misc->gre_protocol || misc->gre_c_present || 85 misc->gre_k_present || misc->gre_s_present); 86 } 87 88 #define DR_MASK_IS_OUTER_MPLS_OVER_GRE_SET(_misc) (\ 89 (_misc)->outer_first_mpls_over_gre_label || \ 90 (_misc)->outer_first_mpls_over_gre_exp || \ 91 (_misc)->outer_first_mpls_over_gre_s_bos || \ 92 (_misc)->outer_first_mpls_over_gre_ttl) 93 94 #define DR_MASK_IS_OUTER_MPLS_OVER_UDP_SET(_misc) (\ 95 (_misc)->outer_first_mpls_over_udp_label || \ 96 (_misc)->outer_first_mpls_over_udp_exp || \ 97 (_misc)->outer_first_mpls_over_udp_s_bos || \ 98 (_misc)->outer_first_mpls_over_udp_ttl) 99 100 static bool 101 dr_mask_is_vxlan_gpe_set(struct mlx5dr_match_misc3 *misc3) 102 { 103 return (misc3->outer_vxlan_gpe_vni || 104 misc3->outer_vxlan_gpe_next_protocol || 105 misc3->outer_vxlan_gpe_flags); 106 } 107 108 static bool 109 dr_matcher_supp_vxlan_gpe(struct mlx5dr_cmd_caps *caps) 110 { 111 return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || 112 (caps->flex_protocols & MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED); 113 } 114 115 static bool 116 dr_mask_is_tnl_vxlan_gpe(struct mlx5dr_match_param *mask, 117 struct mlx5dr_domain *dmn) 118 { 119 return dr_mask_is_vxlan_gpe_set(&mask->misc3) && 120 dr_matcher_supp_vxlan_gpe(&dmn->info.caps); 121 } 122 123 static bool dr_mask_is_tnl_geneve_set(struct mlx5dr_match_misc *misc) 124 { 125 return misc->geneve_vni || 126 misc->geneve_oam || 127 misc->geneve_protocol_type || 128 misc->geneve_opt_len; 129 } 130 131 static bool dr_mask_is_tnl_geneve_tlv_opt(struct mlx5dr_match_misc3 *misc3) 132 { 133 return misc3->geneve_tlv_option_0_data; 134 } 135 136 static bool 137 dr_matcher_supp_flex_parser_ok(struct mlx5dr_cmd_caps *caps) 138 { 139 return caps->flex_parser_ok_bits_supp; 140 } 141 142 static bool dr_mask_is_tnl_geneve_tlv_opt_exist_set(struct mlx5dr_match_misc *misc, 143 struct mlx5dr_domain *dmn) 144 { 145 return dr_matcher_supp_flex_parser_ok(&dmn->info.caps) && 146 misc->geneve_tlv_option_0_exist; 147 } 148 149 static bool 150 dr_matcher_supp_tnl_geneve(struct mlx5dr_cmd_caps *caps) 151 { 152 return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || 153 (caps->flex_protocols & MLX5_FLEX_PARSER_GENEVE_ENABLED); 154 } 155 156 static bool 157 dr_mask_is_tnl_geneve(struct mlx5dr_match_param *mask, 158 struct mlx5dr_domain *dmn) 159 { 160 return dr_mask_is_tnl_geneve_set(&mask->misc) && 161 dr_matcher_supp_tnl_geneve(&dmn->info.caps); 162 } 163 164 static bool dr_mask_is_tnl_gtpu_set(struct mlx5dr_match_misc3 *misc3) 165 { 166 return misc3->gtpu_msg_flags || misc3->gtpu_msg_type || misc3->gtpu_teid; 167 } 168 169 static bool dr_matcher_supp_tnl_gtpu(struct mlx5dr_cmd_caps *caps) 170 { 171 return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_ENABLED; 172 } 173 174 static bool dr_mask_is_tnl_gtpu(struct mlx5dr_match_param *mask, 175 struct mlx5dr_domain *dmn) 176 { 177 return dr_mask_is_tnl_gtpu_set(&mask->misc3) && 178 dr_matcher_supp_tnl_gtpu(&dmn->info.caps); 179 } 180 181 static int dr_matcher_supp_tnl_gtpu_dw_0(struct mlx5dr_cmd_caps *caps) 182 { 183 return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_0_ENABLED; 184 } 185 186 static bool dr_mask_is_tnl_gtpu_dw_0(struct mlx5dr_match_param *mask, 187 struct mlx5dr_domain *dmn) 188 { 189 return mask->misc3.gtpu_dw_0 && 190 dr_matcher_supp_tnl_gtpu_dw_0(&dmn->info.caps); 191 } 192 193 static int dr_matcher_supp_tnl_gtpu_teid(struct mlx5dr_cmd_caps *caps) 194 { 195 return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_TEID_ENABLED; 196 } 197 198 static bool dr_mask_is_tnl_gtpu_teid(struct mlx5dr_match_param *mask, 199 struct mlx5dr_domain *dmn) 200 { 201 return mask->misc3.gtpu_teid && 202 dr_matcher_supp_tnl_gtpu_teid(&dmn->info.caps); 203 } 204 205 static int dr_matcher_supp_tnl_gtpu_dw_2(struct mlx5dr_cmd_caps *caps) 206 { 207 return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_2_ENABLED; 208 } 209 210 static bool dr_mask_is_tnl_gtpu_dw_2(struct mlx5dr_match_param *mask, 211 struct mlx5dr_domain *dmn) 212 { 213 return mask->misc3.gtpu_dw_2 && 214 dr_matcher_supp_tnl_gtpu_dw_2(&dmn->info.caps); 215 } 216 217 static int dr_matcher_supp_tnl_gtpu_first_ext(struct mlx5dr_cmd_caps *caps) 218 { 219 return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_FIRST_EXT_DW_0_ENABLED; 220 } 221 222 static bool dr_mask_is_tnl_gtpu_first_ext(struct mlx5dr_match_param *mask, 223 struct mlx5dr_domain *dmn) 224 { 225 return mask->misc3.gtpu_first_ext_dw_0 && 226 dr_matcher_supp_tnl_gtpu_first_ext(&dmn->info.caps); 227 } 228 229 static bool dr_mask_is_tnl_gtpu_flex_parser_0(struct mlx5dr_match_param *mask, 230 struct mlx5dr_domain *dmn) 231 { 232 struct mlx5dr_cmd_caps *caps = &dmn->info.caps; 233 234 return (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_dw_0) && 235 dr_mask_is_tnl_gtpu_dw_0(mask, dmn)) || 236 (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_teid) && 237 dr_mask_is_tnl_gtpu_teid(mask, dmn)) || 238 (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_dw_2) && 239 dr_mask_is_tnl_gtpu_dw_2(mask, dmn)) || 240 (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_first_ext_dw_0) && 241 dr_mask_is_tnl_gtpu_first_ext(mask, dmn)); 242 } 243 244 static bool dr_mask_is_tnl_gtpu_flex_parser_1(struct mlx5dr_match_param *mask, 245 struct mlx5dr_domain *dmn) 246 { 247 struct mlx5dr_cmd_caps *caps = &dmn->info.caps; 248 249 return (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_dw_0) && 250 dr_mask_is_tnl_gtpu_dw_0(mask, dmn)) || 251 (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_teid) && 252 dr_mask_is_tnl_gtpu_teid(mask, dmn)) || 253 (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_dw_2) && 254 dr_mask_is_tnl_gtpu_dw_2(mask, dmn)) || 255 (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_first_ext_dw_0) && 256 dr_mask_is_tnl_gtpu_first_ext(mask, dmn)); 257 } 258 259 static bool dr_mask_is_tnl_gtpu_any(struct mlx5dr_match_param *mask, 260 struct mlx5dr_domain *dmn) 261 { 262 return dr_mask_is_tnl_gtpu_flex_parser_0(mask, dmn) || 263 dr_mask_is_tnl_gtpu_flex_parser_1(mask, dmn) || 264 dr_mask_is_tnl_gtpu(mask, dmn); 265 } 266 267 static int dr_matcher_supp_icmp_v4(struct mlx5dr_cmd_caps *caps) 268 { 269 return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || 270 (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V4_ENABLED); 271 } 272 273 static int dr_matcher_supp_icmp_v6(struct mlx5dr_cmd_caps *caps) 274 { 275 return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || 276 (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V6_ENABLED); 277 } 278 279 static bool dr_mask_is_icmpv6_set(struct mlx5dr_match_misc3 *misc3) 280 { 281 return (misc3->icmpv6_type || misc3->icmpv6_code || 282 misc3->icmpv6_header_data); 283 } 284 285 static bool dr_mask_is_icmp(struct mlx5dr_match_param *mask, 286 struct mlx5dr_domain *dmn) 287 { 288 if (DR_MASK_IS_ICMPV4_SET(&mask->misc3)) 289 return dr_matcher_supp_icmp_v4(&dmn->info.caps); 290 else if (dr_mask_is_icmpv6_set(&mask->misc3)) 291 return dr_matcher_supp_icmp_v6(&dmn->info.caps); 292 293 return false; 294 } 295 296 static bool dr_mask_is_wqe_metadata_set(struct mlx5dr_match_misc2 *misc2) 297 { 298 return misc2->metadata_reg_a; 299 } 300 301 static bool dr_mask_is_reg_c_0_3_set(struct mlx5dr_match_misc2 *misc2) 302 { 303 return (misc2->metadata_reg_c_0 || misc2->metadata_reg_c_1 || 304 misc2->metadata_reg_c_2 || misc2->metadata_reg_c_3); 305 } 306 307 static bool dr_mask_is_reg_c_4_7_set(struct mlx5dr_match_misc2 *misc2) 308 { 309 return (misc2->metadata_reg_c_4 || misc2->metadata_reg_c_5 || 310 misc2->metadata_reg_c_6 || misc2->metadata_reg_c_7); 311 } 312 313 static bool dr_mask_is_gvmi_or_qpn_set(struct mlx5dr_match_misc *misc) 314 { 315 return (misc->source_sqn || misc->source_port); 316 } 317 318 static bool dr_mask_is_flex_parser_id_0_3_set(u32 flex_parser_id, 319 u32 flex_parser_value) 320 { 321 if (flex_parser_id) 322 return flex_parser_id <= DR_STE_MAX_FLEX_0_ID; 323 324 /* Using flex_parser 0 means that id is zero, thus value must be set. */ 325 return flex_parser_value; 326 } 327 328 static bool dr_mask_is_flex_parser_0_3_set(struct mlx5dr_match_misc4 *misc4) 329 { 330 return (dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_0, 331 misc4->prog_sample_field_value_0) || 332 dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_1, 333 misc4->prog_sample_field_value_1) || 334 dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_2, 335 misc4->prog_sample_field_value_2) || 336 dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_3, 337 misc4->prog_sample_field_value_3)); 338 } 339 340 static bool dr_mask_is_flex_parser_id_4_7_set(u32 flex_parser_id) 341 { 342 return flex_parser_id > DR_STE_MAX_FLEX_0_ID && 343 flex_parser_id <= DR_STE_MAX_FLEX_1_ID; 344 } 345 346 static bool dr_mask_is_flex_parser_4_7_set(struct mlx5dr_match_misc4 *misc4) 347 { 348 return (dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_0) || 349 dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_1) || 350 dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_2) || 351 dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_3)); 352 } 353 354 static int dr_matcher_supp_tnl_mpls_over_gre(struct mlx5dr_cmd_caps *caps) 355 { 356 return caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED; 357 } 358 359 static bool dr_mask_is_tnl_mpls_over_gre(struct mlx5dr_match_param *mask, 360 struct mlx5dr_domain *dmn) 361 { 362 return DR_MASK_IS_OUTER_MPLS_OVER_GRE_SET(&mask->misc2) && 363 dr_matcher_supp_tnl_mpls_over_gre(&dmn->info.caps); 364 } 365 366 static int dr_matcher_supp_tnl_mpls_over_udp(struct mlx5dr_cmd_caps *caps) 367 { 368 return caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED; 369 } 370 371 static bool dr_mask_is_tnl_mpls_over_udp(struct mlx5dr_match_param *mask, 372 struct mlx5dr_domain *dmn) 373 { 374 return DR_MASK_IS_OUTER_MPLS_OVER_UDP_SET(&mask->misc2) && 375 dr_matcher_supp_tnl_mpls_over_udp(&dmn->info.caps); 376 } 377 378 static bool dr_mask_is_tnl_header_0_1_set(struct mlx5dr_match_misc5 *misc5) 379 { 380 return misc5->tunnel_header_0 || misc5->tunnel_header_1; 381 } 382 383 int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, 384 struct mlx5dr_matcher_rx_tx *nic_matcher, 385 enum mlx5dr_ipv outer_ipv, 386 enum mlx5dr_ipv inner_ipv) 387 { 388 nic_matcher->ste_builder = 389 nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; 390 nic_matcher->num_of_builders = 391 nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv]; 392 393 if (!nic_matcher->num_of_builders) { 394 mlx5dr_dbg(matcher->tbl->dmn, 395 "Rule not supported on this matcher due to IP related fields\n"); 396 return -EINVAL; 397 } 398 399 return 0; 400 } 401 402 static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, 403 struct mlx5dr_matcher_rx_tx *nic_matcher, 404 enum mlx5dr_ipv outer_ipv, 405 enum mlx5dr_ipv inner_ipv) 406 { 407 struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; 408 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 409 struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; 410 struct mlx5dr_match_param mask = {}; 411 bool allow_empty_match = false; 412 struct mlx5dr_ste_build *sb; 413 bool inner, rx; 414 int idx = 0; 415 int ret, i; 416 417 sb = nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; 418 rx = nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX; 419 420 /* Create a temporary mask to track and clear used mask fields */ 421 if (matcher->match_criteria & DR_MATCHER_CRITERIA_OUTER) 422 mask.outer = matcher->mask.outer; 423 424 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC) 425 mask.misc = matcher->mask.misc; 426 427 if (matcher->match_criteria & DR_MATCHER_CRITERIA_INNER) 428 mask.inner = matcher->mask.inner; 429 430 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC2) 431 mask.misc2 = matcher->mask.misc2; 432 433 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC3) 434 mask.misc3 = matcher->mask.misc3; 435 436 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC4) 437 mask.misc4 = matcher->mask.misc4; 438 439 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC5) 440 mask.misc5 = matcher->mask.misc5; 441 442 ret = mlx5dr_ste_build_pre_check(dmn, matcher->match_criteria, 443 &matcher->mask, NULL); 444 if (ret) 445 return ret; 446 447 /* Optimize RX pipe by reducing source port match, since 448 * the FDB RX part is connected only to the wire. 449 */ 450 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB && 451 rx && mask.misc.source_port) { 452 mask.misc.source_port = 0; 453 mask.misc.source_eswitch_owner_vhca_id = 0; 454 allow_empty_match = true; 455 } 456 457 /* Outer */ 458 if (matcher->match_criteria & (DR_MATCHER_CRITERIA_OUTER | 459 DR_MATCHER_CRITERIA_MISC | 460 DR_MATCHER_CRITERIA_MISC2 | 461 DR_MATCHER_CRITERIA_MISC3 | 462 DR_MATCHER_CRITERIA_MISC5)) { 463 inner = false; 464 465 if (dr_mask_is_wqe_metadata_set(&mask.misc2)) 466 mlx5dr_ste_build_general_purpose(ste_ctx, &sb[idx++], 467 &mask, inner, rx); 468 469 if (dr_mask_is_reg_c_0_3_set(&mask.misc2)) 470 mlx5dr_ste_build_register_0(ste_ctx, &sb[idx++], 471 &mask, inner, rx); 472 473 if (dr_mask_is_reg_c_4_7_set(&mask.misc2)) 474 mlx5dr_ste_build_register_1(ste_ctx, &sb[idx++], 475 &mask, inner, rx); 476 477 if (dr_mask_is_gvmi_or_qpn_set(&mask.misc) && 478 (dmn->type == MLX5DR_DOMAIN_TYPE_FDB || 479 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX)) { 480 mlx5dr_ste_build_src_gvmi_qpn(ste_ctx, &sb[idx++], 481 &mask, dmn, inner, rx); 482 } 483 484 if (dr_mask_is_smac_set(&mask.outer) && 485 dr_mask_is_dmac_set(&mask.outer)) { 486 mlx5dr_ste_build_eth_l2_src_dst(ste_ctx, &sb[idx++], 487 &mask, inner, rx); 488 } 489 490 if (dr_mask_is_smac_set(&mask.outer)) 491 mlx5dr_ste_build_eth_l2_src(ste_ctx, &sb[idx++], 492 &mask, inner, rx); 493 494 if (DR_MASK_IS_L2_DST(mask.outer, mask.misc, outer)) 495 mlx5dr_ste_build_eth_l2_dst(ste_ctx, &sb[idx++], 496 &mask, inner, rx); 497 498 if (outer_ipv == DR_RULE_IPV6) { 499 if (DR_MASK_IS_DST_IP_SET(&mask.outer)) 500 mlx5dr_ste_build_eth_l3_ipv6_dst(ste_ctx, &sb[idx++], 501 &mask, inner, rx); 502 503 if (DR_MASK_IS_SRC_IP_SET(&mask.outer)) 504 mlx5dr_ste_build_eth_l3_ipv6_src(ste_ctx, &sb[idx++], 505 &mask, inner, rx); 506 507 if (DR_MASK_IS_ETH_L4_SET(mask.outer, mask.misc, outer)) 508 mlx5dr_ste_build_eth_ipv6_l3_l4(ste_ctx, &sb[idx++], 509 &mask, inner, rx); 510 } else { 511 if (dr_mask_is_ipv4_5_tuple_set(&mask.outer)) 512 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(ste_ctx, &sb[idx++], 513 &mask, inner, rx); 514 515 if (dr_mask_is_ttl_set(&mask.outer) || 516 dr_mask_is_ipv4_ihl_set(&mask.outer)) 517 mlx5dr_ste_build_eth_l3_ipv4_misc(ste_ctx, &sb[idx++], 518 &mask, inner, rx); 519 } 520 521 if (dr_mask_is_tnl_vxlan_gpe(&mask, dmn)) 522 mlx5dr_ste_build_tnl_vxlan_gpe(ste_ctx, &sb[idx++], 523 &mask, inner, rx); 524 else if (dr_mask_is_tnl_geneve(&mask, dmn)) { 525 mlx5dr_ste_build_tnl_geneve(ste_ctx, &sb[idx++], 526 &mask, inner, rx); 527 if (dr_mask_is_tnl_geneve_tlv_opt(&mask.misc3)) 528 mlx5dr_ste_build_tnl_geneve_tlv_opt(ste_ctx, &sb[idx++], 529 &mask, &dmn->info.caps, 530 inner, rx); 531 if (dr_mask_is_tnl_geneve_tlv_opt_exist_set(&mask.misc, dmn)) 532 mlx5dr_ste_build_tnl_geneve_tlv_opt_exist(ste_ctx, &sb[idx++], 533 &mask, &dmn->info.caps, 534 inner, rx); 535 } else if (dr_mask_is_tnl_gtpu_any(&mask, dmn)) { 536 if (dr_mask_is_tnl_gtpu_flex_parser_0(&mask, dmn)) 537 mlx5dr_ste_build_tnl_gtpu_flex_parser_0(ste_ctx, &sb[idx++], 538 &mask, &dmn->info.caps, 539 inner, rx); 540 541 if (dr_mask_is_tnl_gtpu_flex_parser_1(&mask, dmn)) 542 mlx5dr_ste_build_tnl_gtpu_flex_parser_1(ste_ctx, &sb[idx++], 543 &mask, &dmn->info.caps, 544 inner, rx); 545 546 if (dr_mask_is_tnl_gtpu(&mask, dmn)) 547 mlx5dr_ste_build_tnl_gtpu(ste_ctx, &sb[idx++], 548 &mask, inner, rx); 549 } else if (dr_mask_is_tnl_header_0_1_set(&mask.misc5)) { 550 mlx5dr_ste_build_tnl_header_0_1(ste_ctx, &sb[idx++], 551 &mask, inner, rx); 552 } 553 554 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer)) 555 mlx5dr_ste_build_eth_l4_misc(ste_ctx, &sb[idx++], 556 &mask, inner, rx); 557 558 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, outer)) 559 mlx5dr_ste_build_mpls(ste_ctx, &sb[idx++], 560 &mask, inner, rx); 561 562 if (dr_mask_is_tnl_mpls_over_gre(&mask, dmn)) 563 mlx5dr_ste_build_tnl_mpls_over_gre(ste_ctx, &sb[idx++], 564 &mask, &dmn->info.caps, 565 inner, rx); 566 else if (dr_mask_is_tnl_mpls_over_udp(&mask, dmn)) 567 mlx5dr_ste_build_tnl_mpls_over_udp(ste_ctx, &sb[idx++], 568 &mask, &dmn->info.caps, 569 inner, rx); 570 571 if (dr_mask_is_icmp(&mask, dmn)) 572 mlx5dr_ste_build_icmp(ste_ctx, &sb[idx++], 573 &mask, &dmn->info.caps, 574 inner, rx); 575 576 if (dr_mask_is_tnl_gre_set(&mask.misc)) 577 mlx5dr_ste_build_tnl_gre(ste_ctx, &sb[idx++], 578 &mask, inner, rx); 579 } 580 581 /* Inner */ 582 if (matcher->match_criteria & (DR_MATCHER_CRITERIA_INNER | 583 DR_MATCHER_CRITERIA_MISC | 584 DR_MATCHER_CRITERIA_MISC2 | 585 DR_MATCHER_CRITERIA_MISC3)) { 586 inner = true; 587 588 if (dr_mask_is_eth_l2_tnl_set(&mask.misc)) 589 mlx5dr_ste_build_eth_l2_tnl(ste_ctx, &sb[idx++], 590 &mask, inner, rx); 591 592 if (dr_mask_is_smac_set(&mask.inner) && 593 dr_mask_is_dmac_set(&mask.inner)) { 594 mlx5dr_ste_build_eth_l2_src_dst(ste_ctx, &sb[idx++], 595 &mask, inner, rx); 596 } 597 598 if (dr_mask_is_smac_set(&mask.inner)) 599 mlx5dr_ste_build_eth_l2_src(ste_ctx, &sb[idx++], 600 &mask, inner, rx); 601 602 if (DR_MASK_IS_L2_DST(mask.inner, mask.misc, inner)) 603 mlx5dr_ste_build_eth_l2_dst(ste_ctx, &sb[idx++], 604 &mask, inner, rx); 605 606 if (inner_ipv == DR_RULE_IPV6) { 607 if (DR_MASK_IS_DST_IP_SET(&mask.inner)) 608 mlx5dr_ste_build_eth_l3_ipv6_dst(ste_ctx, &sb[idx++], 609 &mask, inner, rx); 610 611 if (DR_MASK_IS_SRC_IP_SET(&mask.inner)) 612 mlx5dr_ste_build_eth_l3_ipv6_src(ste_ctx, &sb[idx++], 613 &mask, inner, rx); 614 615 if (DR_MASK_IS_ETH_L4_SET(mask.inner, mask.misc, inner)) 616 mlx5dr_ste_build_eth_ipv6_l3_l4(ste_ctx, &sb[idx++], 617 &mask, inner, rx); 618 } else { 619 if (dr_mask_is_ipv4_5_tuple_set(&mask.inner)) 620 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(ste_ctx, &sb[idx++], 621 &mask, inner, rx); 622 623 if (dr_mask_is_ttl_set(&mask.inner) || 624 dr_mask_is_ipv4_ihl_set(&mask.inner)) 625 mlx5dr_ste_build_eth_l3_ipv4_misc(ste_ctx, &sb[idx++], 626 &mask, inner, rx); 627 } 628 629 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, inner)) 630 mlx5dr_ste_build_eth_l4_misc(ste_ctx, &sb[idx++], 631 &mask, inner, rx); 632 633 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, inner)) 634 mlx5dr_ste_build_mpls(ste_ctx, &sb[idx++], 635 &mask, inner, rx); 636 637 if (dr_mask_is_tnl_mpls_over_gre(&mask, dmn)) 638 mlx5dr_ste_build_tnl_mpls_over_gre(ste_ctx, &sb[idx++], 639 &mask, &dmn->info.caps, 640 inner, rx); 641 else if (dr_mask_is_tnl_mpls_over_udp(&mask, dmn)) 642 mlx5dr_ste_build_tnl_mpls_over_udp(ste_ctx, &sb[idx++], 643 &mask, &dmn->info.caps, 644 inner, rx); 645 } 646 647 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC4) { 648 if (dr_mask_is_flex_parser_0_3_set(&mask.misc4)) 649 mlx5dr_ste_build_flex_parser_0(ste_ctx, &sb[idx++], 650 &mask, false, rx); 651 652 if (dr_mask_is_flex_parser_4_7_set(&mask.misc4)) 653 mlx5dr_ste_build_flex_parser_1(ste_ctx, &sb[idx++], 654 &mask, false, rx); 655 } 656 657 /* Empty matcher, takes all */ 658 if ((!idx && allow_empty_match) || 659 matcher->match_criteria == DR_MATCHER_CRITERIA_EMPTY) 660 mlx5dr_ste_build_empty_always_hit(&sb[idx++], rx); 661 662 if (idx == 0) { 663 mlx5dr_err(dmn, "Cannot generate any valid rules from mask\n"); 664 return -EINVAL; 665 } 666 667 /* Check that all mask fields were consumed */ 668 for (i = 0; i < sizeof(struct mlx5dr_match_param); i++) { 669 if (((u8 *)&mask)[i] != 0) { 670 mlx5dr_dbg(dmn, "Mask contains unsupported parameters\n"); 671 return -EOPNOTSUPP; 672 } 673 } 674 675 nic_matcher->ste_builder = sb; 676 nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv] = idx; 677 678 return 0; 679 } 680 681 static int dr_nic_matcher_connect(struct mlx5dr_domain *dmn, 682 struct mlx5dr_matcher_rx_tx *curr_nic_matcher, 683 struct mlx5dr_matcher_rx_tx *next_nic_matcher, 684 struct mlx5dr_matcher_rx_tx *prev_nic_matcher) 685 { 686 struct mlx5dr_table_rx_tx *nic_tbl = curr_nic_matcher->nic_tbl; 687 struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; 688 struct mlx5dr_htbl_connect_info info; 689 struct mlx5dr_ste_htbl *prev_htbl; 690 int ret; 691 692 /* Connect end anchor hash table to next_htbl or to the default address */ 693 if (next_nic_matcher) { 694 info.type = CONNECT_HIT; 695 info.hit_next_htbl = next_nic_matcher->s_htbl; 696 } else { 697 info.type = CONNECT_MISS; 698 info.miss_icm_addr = nic_tbl->default_icm_addr; 699 } 700 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, 701 curr_nic_matcher->e_anchor, 702 &info, info.type == CONNECT_HIT); 703 if (ret) 704 return ret; 705 706 /* Connect start hash table to end anchor */ 707 info.type = CONNECT_MISS; 708 info.miss_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(curr_nic_matcher->e_anchor->chunk); 709 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, 710 curr_nic_matcher->s_htbl, 711 &info, false); 712 if (ret) 713 return ret; 714 715 /* Connect previous hash table to matcher start hash table */ 716 if (prev_nic_matcher) 717 prev_htbl = prev_nic_matcher->e_anchor; 718 else 719 prev_htbl = nic_tbl->s_anchor; 720 721 info.type = CONNECT_HIT; 722 info.hit_next_htbl = curr_nic_matcher->s_htbl; 723 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_htbl, 724 &info, true); 725 if (ret) 726 return ret; 727 728 /* Update the pointing ste and next hash table */ 729 curr_nic_matcher->s_htbl->pointing_ste = prev_htbl->chunk->ste_arr; 730 prev_htbl->chunk->ste_arr[0].next_htbl = curr_nic_matcher->s_htbl; 731 732 if (next_nic_matcher) { 733 next_nic_matcher->s_htbl->pointing_ste = 734 curr_nic_matcher->e_anchor->chunk->ste_arr; 735 curr_nic_matcher->e_anchor->chunk->ste_arr[0].next_htbl = 736 next_nic_matcher->s_htbl; 737 } 738 739 return 0; 740 } 741 742 int mlx5dr_matcher_add_to_tbl_nic(struct mlx5dr_domain *dmn, 743 struct mlx5dr_matcher_rx_tx *nic_matcher) 744 { 745 struct mlx5dr_matcher_rx_tx *next_nic_matcher, *prev_nic_matcher, *tmp_nic_matcher; 746 struct mlx5dr_table_rx_tx *nic_tbl = nic_matcher->nic_tbl; 747 bool first = true; 748 int ret; 749 750 /* If the nic matcher is already on its parent nic table list, 751 * then it is already connected to the chain of nic matchers. 752 */ 753 if (!list_empty(&nic_matcher->list_node)) 754 return 0; 755 756 next_nic_matcher = NULL; 757 list_for_each_entry(tmp_nic_matcher, &nic_tbl->nic_matcher_list, list_node) { 758 if (tmp_nic_matcher->prio >= nic_matcher->prio) { 759 next_nic_matcher = tmp_nic_matcher; 760 break; 761 } 762 first = false; 763 } 764 765 prev_nic_matcher = NULL; 766 if (next_nic_matcher && !first) 767 prev_nic_matcher = list_prev_entry(next_nic_matcher, list_node); 768 else if (!first) 769 prev_nic_matcher = list_last_entry(&nic_tbl->nic_matcher_list, 770 struct mlx5dr_matcher_rx_tx, 771 list_node); 772 773 ret = dr_nic_matcher_connect(dmn, nic_matcher, 774 next_nic_matcher, prev_nic_matcher); 775 if (ret) 776 return ret; 777 778 if (prev_nic_matcher) 779 list_add(&nic_matcher->list_node, &prev_nic_matcher->list_node); 780 else if (next_nic_matcher) 781 list_add_tail(&nic_matcher->list_node, &next_nic_matcher->list_node); 782 else 783 list_add(&nic_matcher->list_node, &nic_matcher->nic_tbl->nic_matcher_list); 784 785 return ret; 786 } 787 788 static void dr_matcher_uninit_nic(struct mlx5dr_matcher_rx_tx *nic_matcher) 789 { 790 mlx5dr_htbl_put(nic_matcher->s_htbl); 791 mlx5dr_htbl_put(nic_matcher->e_anchor); 792 } 793 794 static void dr_matcher_uninit_fdb(struct mlx5dr_matcher *matcher) 795 { 796 dr_matcher_uninit_nic(&matcher->rx); 797 dr_matcher_uninit_nic(&matcher->tx); 798 } 799 800 static void dr_matcher_uninit(struct mlx5dr_matcher *matcher) 801 { 802 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 803 804 switch (dmn->type) { 805 case MLX5DR_DOMAIN_TYPE_NIC_RX: 806 dr_matcher_uninit_nic(&matcher->rx); 807 break; 808 case MLX5DR_DOMAIN_TYPE_NIC_TX: 809 dr_matcher_uninit_nic(&matcher->tx); 810 break; 811 case MLX5DR_DOMAIN_TYPE_FDB: 812 dr_matcher_uninit_fdb(matcher); 813 break; 814 default: 815 WARN_ON(true); 816 break; 817 } 818 } 819 820 static int dr_matcher_set_all_ste_builders(struct mlx5dr_matcher *matcher, 821 struct mlx5dr_matcher_rx_tx *nic_matcher) 822 { 823 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 824 825 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV4); 826 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV6); 827 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV4); 828 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV6); 829 830 if (!nic_matcher->ste_builder) { 831 mlx5dr_err(dmn, "Cannot generate IPv4 or IPv6 rules with given mask\n"); 832 return -EINVAL; 833 } 834 835 return 0; 836 } 837 838 static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher, 839 struct mlx5dr_matcher_rx_tx *nic_matcher) 840 { 841 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 842 int ret; 843 844 nic_matcher->prio = matcher->prio; 845 INIT_LIST_HEAD(&nic_matcher->list_node); 846 847 ret = dr_matcher_set_all_ste_builders(matcher, nic_matcher); 848 if (ret) 849 return ret; 850 851 nic_matcher->e_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, 852 DR_CHUNK_SIZE_1, 853 MLX5DR_STE_LU_TYPE_DONT_CARE, 854 0); 855 if (!nic_matcher->e_anchor) 856 return -ENOMEM; 857 858 nic_matcher->s_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, 859 DR_CHUNK_SIZE_1, 860 nic_matcher->ste_builder[0].lu_type, 861 nic_matcher->ste_builder[0].byte_mask); 862 if (!nic_matcher->s_htbl) { 863 ret = -ENOMEM; 864 goto free_e_htbl; 865 } 866 867 /* make sure the tables exist while empty */ 868 mlx5dr_htbl_get(nic_matcher->s_htbl); 869 mlx5dr_htbl_get(nic_matcher->e_anchor); 870 871 return 0; 872 873 free_e_htbl: 874 mlx5dr_ste_htbl_free(nic_matcher->e_anchor); 875 return ret; 876 } 877 878 static int dr_matcher_init_fdb(struct mlx5dr_matcher *matcher) 879 { 880 int ret; 881 882 ret = dr_matcher_init_nic(matcher, &matcher->rx); 883 if (ret) 884 return ret; 885 886 ret = dr_matcher_init_nic(matcher, &matcher->tx); 887 if (ret) 888 goto uninit_nic_rx; 889 890 return 0; 891 892 uninit_nic_rx: 893 dr_matcher_uninit_nic(&matcher->rx); 894 return ret; 895 } 896 897 static int dr_matcher_copy_param(struct mlx5dr_matcher *matcher, 898 struct mlx5dr_match_parameters *mask) 899 { 900 struct mlx5dr_domain *dmn = matcher->tbl->dmn; 901 struct mlx5dr_match_parameters consumed_mask; 902 int i, ret = 0; 903 904 if (matcher->match_criteria >= DR_MATCHER_CRITERIA_MAX) { 905 mlx5dr_err(dmn, "Invalid match criteria attribute\n"); 906 return -EINVAL; 907 } 908 909 if (mask) { 910 if (mask->match_sz > DR_SZ_MATCH_PARAM) { 911 mlx5dr_err(dmn, "Invalid match size attribute\n"); 912 return -EINVAL; 913 } 914 915 consumed_mask.match_buf = kzalloc(mask->match_sz, GFP_KERNEL); 916 if (!consumed_mask.match_buf) 917 return -ENOMEM; 918 919 consumed_mask.match_sz = mask->match_sz; 920 memcpy(consumed_mask.match_buf, mask->match_buf, mask->match_sz); 921 mlx5dr_ste_copy_param(matcher->match_criteria, 922 &matcher->mask, &consumed_mask, true); 923 924 /* Check that all mask data was consumed */ 925 for (i = 0; i < consumed_mask.match_sz; i++) { 926 if (!((u8 *)consumed_mask.match_buf)[i]) 927 continue; 928 929 mlx5dr_dbg(dmn, 930 "Match param mask contains unsupported parameters\n"); 931 ret = -EOPNOTSUPP; 932 break; 933 } 934 935 kfree(consumed_mask.match_buf); 936 } 937 938 return ret; 939 } 940 941 static int dr_matcher_init(struct mlx5dr_matcher *matcher, 942 struct mlx5dr_match_parameters *mask) 943 { 944 struct mlx5dr_table *tbl = matcher->tbl; 945 struct mlx5dr_domain *dmn = tbl->dmn; 946 int ret; 947 948 ret = dr_matcher_copy_param(matcher, mask); 949 if (ret) 950 return ret; 951 952 switch (dmn->type) { 953 case MLX5DR_DOMAIN_TYPE_NIC_RX: 954 matcher->rx.nic_tbl = &tbl->rx; 955 ret = dr_matcher_init_nic(matcher, &matcher->rx); 956 break; 957 case MLX5DR_DOMAIN_TYPE_NIC_TX: 958 matcher->tx.nic_tbl = &tbl->tx; 959 ret = dr_matcher_init_nic(matcher, &matcher->tx); 960 break; 961 case MLX5DR_DOMAIN_TYPE_FDB: 962 matcher->rx.nic_tbl = &tbl->rx; 963 matcher->tx.nic_tbl = &tbl->tx; 964 ret = dr_matcher_init_fdb(matcher); 965 break; 966 default: 967 WARN_ON(true); 968 ret = -EINVAL; 969 } 970 971 return ret; 972 } 973 974 static void dr_matcher_add_to_dbg_list(struct mlx5dr_matcher *matcher) 975 { 976 mutex_lock(&matcher->tbl->dmn->dump_info.dbg_mutex); 977 list_add(&matcher->list_node, &matcher->tbl->matcher_list); 978 mutex_unlock(&matcher->tbl->dmn->dump_info.dbg_mutex); 979 } 980 981 static void dr_matcher_remove_from_dbg_list(struct mlx5dr_matcher *matcher) 982 { 983 mutex_lock(&matcher->tbl->dmn->dump_info.dbg_mutex); 984 list_del(&matcher->list_node); 985 mutex_unlock(&matcher->tbl->dmn->dump_info.dbg_mutex); 986 } 987 988 struct mlx5dr_matcher * 989 mlx5dr_matcher_create(struct mlx5dr_table *tbl, 990 u32 priority, 991 u8 match_criteria_enable, 992 struct mlx5dr_match_parameters *mask) 993 { 994 struct mlx5dr_matcher *matcher; 995 int ret; 996 997 refcount_inc(&tbl->refcount); 998 999 matcher = kzalloc(sizeof(*matcher), GFP_KERNEL); 1000 if (!matcher) 1001 goto dec_ref; 1002 1003 matcher->tbl = tbl; 1004 matcher->prio = priority; 1005 matcher->match_criteria = match_criteria_enable; 1006 refcount_set(&matcher->refcount, 1); 1007 INIT_LIST_HEAD(&matcher->list_node); 1008 INIT_LIST_HEAD(&matcher->dbg_rule_list); 1009 1010 mlx5dr_domain_lock(tbl->dmn); 1011 1012 ret = dr_matcher_init(matcher, mask); 1013 if (ret) 1014 goto free_matcher; 1015 1016 dr_matcher_add_to_dbg_list(matcher); 1017 1018 mlx5dr_domain_unlock(tbl->dmn); 1019 1020 return matcher; 1021 1022 free_matcher: 1023 mlx5dr_domain_unlock(tbl->dmn); 1024 kfree(matcher); 1025 dec_ref: 1026 refcount_dec(&tbl->refcount); 1027 return NULL; 1028 } 1029 1030 static int dr_matcher_disconnect_nic(struct mlx5dr_domain *dmn, 1031 struct mlx5dr_table_rx_tx *nic_tbl, 1032 struct mlx5dr_matcher_rx_tx *next_nic_matcher, 1033 struct mlx5dr_matcher_rx_tx *prev_nic_matcher) 1034 { 1035 struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; 1036 struct mlx5dr_htbl_connect_info info; 1037 struct mlx5dr_ste_htbl *prev_anchor; 1038 1039 if (prev_nic_matcher) 1040 prev_anchor = prev_nic_matcher->e_anchor; 1041 else 1042 prev_anchor = nic_tbl->s_anchor; 1043 1044 /* Connect previous anchor hash table to next matcher or to the default address */ 1045 if (next_nic_matcher) { 1046 info.type = CONNECT_HIT; 1047 info.hit_next_htbl = next_nic_matcher->s_htbl; 1048 next_nic_matcher->s_htbl->pointing_ste = prev_anchor->chunk->ste_arr; 1049 prev_anchor->chunk->ste_arr[0].next_htbl = next_nic_matcher->s_htbl; 1050 } else { 1051 info.type = CONNECT_MISS; 1052 info.miss_icm_addr = nic_tbl->default_icm_addr; 1053 prev_anchor->chunk->ste_arr[0].next_htbl = NULL; 1054 } 1055 1056 return mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_anchor, 1057 &info, true); 1058 } 1059 1060 int mlx5dr_matcher_remove_from_tbl_nic(struct mlx5dr_domain *dmn, 1061 struct mlx5dr_matcher_rx_tx *nic_matcher) 1062 { 1063 struct mlx5dr_matcher_rx_tx *prev_nic_matcher, *next_nic_matcher; 1064 struct mlx5dr_table_rx_tx *nic_tbl = nic_matcher->nic_tbl; 1065 int ret; 1066 1067 /* If the nic matcher is not on its parent nic table list, 1068 * then it is detached - no need to disconnect it. 1069 */ 1070 if (list_empty(&nic_matcher->list_node)) 1071 return 0; 1072 1073 if (list_is_last(&nic_matcher->list_node, &nic_tbl->nic_matcher_list)) 1074 next_nic_matcher = NULL; 1075 else 1076 next_nic_matcher = list_next_entry(nic_matcher, list_node); 1077 1078 if (nic_matcher->list_node.prev == &nic_tbl->nic_matcher_list) 1079 prev_nic_matcher = NULL; 1080 else 1081 prev_nic_matcher = list_prev_entry(nic_matcher, list_node); 1082 1083 ret = dr_matcher_disconnect_nic(dmn, nic_tbl, next_nic_matcher, prev_nic_matcher); 1084 if (ret) 1085 return ret; 1086 1087 list_del_init(&nic_matcher->list_node); 1088 return 0; 1089 } 1090 1091 int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher) 1092 { 1093 struct mlx5dr_table *tbl = matcher->tbl; 1094 1095 if (WARN_ON_ONCE(refcount_read(&matcher->refcount) > 1)) 1096 return -EBUSY; 1097 1098 mlx5dr_domain_lock(tbl->dmn); 1099 1100 dr_matcher_remove_from_dbg_list(matcher); 1101 dr_matcher_uninit(matcher); 1102 refcount_dec(&matcher->tbl->refcount); 1103 1104 mlx5dr_domain_unlock(tbl->dmn); 1105 kfree(matcher); 1106 1107 return 0; 1108 } 1109