FILE
rule.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.c
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ 3 4#include "internal.h" 5 6void mlx5hws_rule_skip(struct mlx5hws_matcher *matcher, u32 flow_source, 7 bool *skip_rx, bool *skip_tx) 8{ 9 /* By default FDB rules are added to both RX and TX */ 10 *skip_rx = false; 11 *skip_tx = false; 12 13 if (flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT) { 14 *skip_rx = true; 15 return; 16 } 17 18 if (flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK) { 19 *skip_tx = true; 20 return; 21 } 22 23 /* If no flow source was set for current rule, 24 * check for flow source in matcher attributes. 25 */ 26 *skip_tx = matcher->attr.optimize_flow_src == 27 MLX5HWS_MATCHER_FLOW_SRC_WIRE; 28 *skip_rx = matcher->attr.optimize_flow_src == 29 MLX5HWS_MATCHER_FLOW_SRC_VPORT; 30} 31 32static void 33hws_rule_update_copy_tag(struct mlx5hws_rule *rule, 34 struct mlx5hws_wqe_gta_data_seg_ste *wqe_data, 35 bool is_jumbo) 36{ 37 struct mlx5hws_rule_match_tag *tag; 38 39 if (!mlx5hws_matcher_is_resizable(rule->matcher)) { 40 tag = &rule->tag; 41 } else { 42 struct mlx5hws_wqe_gta_data_seg_ste *data_seg = 43 (struct mlx5hws_wqe_gta_data_seg_ste *)(void *)rule->resize_info->data_seg; 44 tag = (struct mlx5hws_rule_match_tag *)(void *)data_seg->action; 45 } 46 47 if (is_jumbo) 48 memcpy(wqe_data->jumbo, tag->jumbo, MLX5HWS_JUMBO_TAG_SZ); 49 else 50 memcpy(wqe_data->tag, tag->match, MLX5HWS_MATCH_TAG_SZ); 51} 52 53static void hws_rule_init_dep_wqe(struct mlx5hws_send_ring_dep_wqe *dep_wqe, 54 struct mlx5hws_rule *rule, 55 struct mlx5hws_match_template *mt, 56 struct mlx5hws_rule_attr *attr) 57{ 58 struct mlx5hws_matcher *matcher = rule->matcher; 59 struct mlx5hws_table *tbl = matcher->tbl; 60 bool skip_rx, skip_tx; 61 62 dep_wqe->rule = rule; 63 dep_wqe->user_data = attr->user_data; 64 dep_wqe->direct_index = mlx5hws_matcher_is_insert_by_idx(matcher) ? 65 attr->rule_idx : 0; 66 67 if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) { 68 mlx5hws_rule_skip(matcher, attr->flow_source, 69 &skip_rx, &skip_tx); 70 71 if (!skip_rx) { 72 dep_wqe->rtc_0 = matcher->match_ste.rtc_0_id; 73 dep_wqe->retry_rtc_0 = matcher->col_matcher ? 74 matcher->col_matcher->match_ste.rtc_0_id : 0; 75 } else { 76 dep_wqe->rtc_0 = 0; 77 dep_wqe->retry_rtc_0 = 0; 78 } 79 80 if (!skip_tx) { 81 dep_wqe->rtc_1 = matcher->match_ste.rtc_1_id; 82 dep_wqe->retry_rtc_1 = matcher->col_matcher ? 83 matcher->col_matcher->match_ste.rtc_1_id : 0; 84 } else { 85 dep_wqe->rtc_1 = 0; 86 dep_wqe->retry_rtc_1 = 0; 87 } 88 } else { 89 pr_warn("HWS: invalid tbl->type: %d\n", tbl->type); 90 } 91} 92 93static void hws_rule_move_get_rtc(struct mlx5hws_rule *rule, 94 struct mlx5hws_send_ste_attr *ste_attr) 95{ 96 struct mlx5hws_matcher *dst_matcher = rule->matcher->resize_dst; 97 98 if (rule->resize_info->rtc_0) { 99 ste_attr->rtc_0 = dst_matcher->match_ste.rtc_0_id; 100 ste_attr->retry_rtc_0 = dst_matcher->col_matcher ? 101 dst_matcher->col_matcher->match_ste.rtc_0_id : 0; 102 } 103 if (rule->resize_info->rtc_1) { 104 ste_attr->rtc_1 = dst_matcher->match_ste.rtc_1_id; 105 ste_attr->retry_rtc_1 = dst_matcher->col_matcher ? 106 dst_matcher->col_matcher->match_ste.rtc_1_id : 0; 107 } 108} 109 110static void hws_rule_gen_comp(struct mlx5hws_send_engine *queue, 111 struct mlx5hws_rule *rule, 112 bool err, 113 void *user_data, 114 enum mlx5hws_rule_status rule_status_on_succ) 115{ 116 enum mlx5hws_flow_op_status comp_status; 117 118 if (!err) { 119 comp_status = MLX5HWS_FLOW_OP_SUCCESS; 120 rule->status = rule_status_on_succ; 121 } else { 122 comp_status = MLX5HWS_FLOW_OP_ERROR; 123 rule->status = MLX5HWS_RULE_STATUS_FAILED; 124 } 125 126 mlx5hws_send_engine_inc_rule(queue); 127 mlx5hws_send_engine_gen_comp(queue, user_data, comp_status); 128} 129 130static void 131hws_rule_save_resize_info(struct mlx5hws_rule *rule, 132 struct mlx5hws_send_ste_attr *ste_attr) 133{ 134 if (!mlx5hws_matcher_is_resizable(rule->matcher)) 135 return; 136 137 /* resize_info might already exist (if we're in update flow) */ 138 if (likely(!rule->resize_info)) { 139 rule->resize_info = kzalloc(sizeof(*rule->resize_info), GFP_KERNEL); 140 if (unlikely(!rule->resize_info)) { 141 pr_warn("HWS: resize info isn't allocated for rule\n"); 142 return; 143 } 144 } 145 146 memcpy(rule->resize_info->ctrl_seg, ste_attr->wqe_ctrl, 147 sizeof(rule->resize_info->ctrl_seg)); 148 memcpy(rule->resize_info->data_seg, ste_attr->wqe_data, 149 sizeof(rule->resize_info->data_seg)); 150} 151 152void mlx5hws_rule_clear_resize_info(struct mlx5hws_rule *rule) 153{ 154 if (mlx5hws_matcher_is_resizable(rule->matcher) && 155 rule->resize_info) { 156 kfree(rule->resize_info); 157 rule->resize_info = NULL; 158 } 159} 160 161static void 162hws_rule_save_delete_info(struct mlx5hws_rule *rule, 163 struct mlx5hws_send_ste_attr *ste_attr) 164{ 165 struct mlx5hws_match_template *mt = rule->matcher->mt; 166 bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); 167 168 if (mlx5hws_matcher_is_resizable(rule->matcher)) 169 return; 170 171 if (is_jumbo) 172 memcpy(&rule->tag.jumbo, ste_attr->wqe_data->jumbo, MLX5HWS_JUMBO_TAG_SZ); 173 else 174 memcpy(&rule->tag.match, ste_attr->wqe_data->tag, MLX5HWS_MATCH_TAG_SZ); 175} 176 177static void 178hws_rule_clear_delete_info(struct mlx5hws_rule *rule) 179{ 180 /* nothing to do here */ 181} 182 183static void 184hws_rule_load_delete_info(struct mlx5hws_rule *rule, 185 struct mlx5hws_send_ste_attr *ste_attr) 186{ 187 if (unlikely(!mlx5hws_matcher_is_resizable(rule->matcher))) { 188 ste_attr->wqe_tag = &rule->tag; 189 } else { 190 struct mlx5hws_wqe_gta_data_seg_ste *data_seg = 191 (struct mlx5hws_wqe_gta_data_seg_ste *)(void *)rule->resize_info->data_seg; 192 struct mlx5hws_rule_match_tag *tag = 193 (struct mlx5hws_rule_match_tag *)(void *)data_seg->action; 194 ste_attr->wqe_tag = tag; 195 } 196} 197 198static int mlx5hws_rule_alloc_action_ste(struct mlx5hws_rule *rule, 199 u16 queue_id, bool skip_rx, 200 bool skip_tx) 201{ 202 struct mlx5hws_matcher *matcher = rule->matcher; 203 struct mlx5hws_context *ctx = matcher->tbl->ctx; 204 205 rule->action_ste.ste.order = 206 ilog2(roundup_pow_of_two(matcher->num_of_action_stes)); 207 return mlx5hws_action_ste_chunk_alloc(&ctx->action_ste_pool[queue_id], 208 skip_rx, skip_tx, 209 &rule->action_ste); 210} 211 212void mlx5hws_rule_free_action_ste(struct mlx5hws_action_ste_chunk *action_ste) 213{ 214 if (!action_ste->action_tbl) 215 return; 216 217 /* This release is safe only when the rule match STE was deleted 218 * (when the rule is being deleted) or replaced with the new STE that 219 * isn't pointing to old action STEs (when the rule is being updated). 220 */ 221 mlx5hws_action_ste_chunk_free(action_ste); 222} 223 224static void hws_rule_create_init(struct mlx5hws_rule *rule, 225 struct mlx5hws_send_ste_attr *ste_attr, 226 struct mlx5hws_actions_apply_data *apply, 227 bool is_update) 228{ 229 struct mlx5hws_matcher *matcher = rule->matcher; 230 struct mlx5hws_table *tbl = matcher->tbl; 231 struct mlx5hws_context *ctx = tbl->ctx; 232 233 /* Init rule before reuse */ 234 if (!is_update) { 235 /* In update we use these rtc's */ 236 rule->rtc_0 = 0; 237 rule->rtc_1 = 0; 238 239 rule->status = MLX5HWS_RULE_STATUS_CREATING; 240 } else { 241 rule->status = MLX5HWS_RULE_STATUS_UPDATING; 242 /* Save the old action STE info so we can free it after writing 243 * new action STEs and a corresponding match STE. 244 */ 245 rule->old_action_ste = rule->action_ste; 246 } 247 248 rule->pending_wqes = 0; 249 250 /* Init default send STE attributes */ 251 ste_attr->gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; 252 ste_attr->send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; 253 ste_attr->send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; 254 ste_attr->send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; 255 256 /* Init default action apply */ 257 apply->tbl_type = tbl->type; 258 apply->common_res = &ctx->common_res; 259 apply->require_dep = 0; 260} 261 262static void hws_rule_move_init(struct mlx5hws_rule *rule, 263 struct mlx5hws_rule_attr *attr) 264{ 265 /* Save the old RTC IDs to be later used in match STE delete */ 266 rule->resize_info->rtc_0 = rule->rtc_0; 267 rule->resize_info->rtc_1 = rule->rtc_1; 268 rule->resize_info->rule_idx = attr->rule_idx; 269 270 rule->rtc_0 = 0; 271 rule->rtc_1 = 0; 272 273 rule->pending_wqes = 0; 274 rule->status = MLX5HWS_RULE_STATUS_CREATING; 275 rule->resize_info->state = MLX5HWS_RULE_RESIZE_STATE_WRITING; 276} 277 278bool mlx5hws_rule_move_in_progress(struct mlx5hws_rule *rule) 279{ 280 return mlx5hws_matcher_is_in_resize(rule->matcher) && 281 rule->resize_info && 282 rule->resize_info->state != MLX5HWS_RULE_RESIZE_STATE_IDLE; 283} 284 285static int hws_rule_create_hws(struct mlx5hws_rule *rule, 286 struct mlx5hws_rule_attr *attr, 287 u8 mt_idx, 288 u32 *match_param, 289 u8 at_idx, 290 struct mlx5hws_rule_action rule_actions[]) 291{ 292 struct mlx5hws_action_template *at = &rule->matcher->at[at_idx]; 293 struct mlx5hws_match_template *mt = &rule->matcher->mt[mt_idx]; 294 bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); 295 struct mlx5hws_matcher *matcher = rule->matcher; 296 struct mlx5hws_context *ctx = matcher->tbl->ctx; 297 struct mlx5hws_send_ste_attr ste_attr = {0}; 298 struct mlx5hws_send_ring_dep_wqe *dep_wqe; 299 struct mlx5hws_actions_wqe_setter *setter; 300 struct mlx5hws_actions_apply_data apply; 301 struct mlx5hws_send_engine *queue; 302 u8 total_stes, action_stes; 303 bool is_update; 304 int i, ret; 305 306 is_update = !match_param; 307 308 setter = &at->setters[at->num_of_action_stes]; 309 total_stes = at->num_of_action_stes + (is_jumbo && !at->only_term); 310 action_stes = total_stes - 1; 311 312 queue = &ctx->send_queue[attr->queue_id]; 313 if (unlikely(mlx5hws_send_engine_err(queue))) 314 return -EIO; 315 316 hws_rule_create_init(rule, &ste_attr, &apply, is_update); 317 318 /* Allocate dependent match WQE since rule might have dependent writes. 319 * The queued dependent WQE can be later aborted or kept as a dependency. 320 * dep_wqe buffers (ctrl, data) are also reused for all STE writes. 321 */ 322 dep_wqe = mlx5hws_send_add_new_dep_wqe(queue); 323 hws_rule_init_dep_wqe(dep_wqe, rule, mt, attr); 324 325 ste_attr.wqe_ctrl = &dep_wqe->wqe_ctrl; 326 ste_attr.wqe_data = &dep_wqe->wqe_data; 327 apply.wqe_ctrl = &dep_wqe->wqe_ctrl; 328 apply.wqe_data = (__force __be32 *)&dep_wqe->wqe_data; 329 apply.rule_action = rule_actions; 330 apply.queue = queue; 331 332 if (action_stes) { 333 /* Allocate action STEs for rules that need more than match STE */ 334 ret = mlx5hws_rule_alloc_action_ste(rule, attr->queue_id, 335 !!ste_attr.rtc_0, 336 !!ste_attr.rtc_1); 337 if (ret) { 338 mlx5hws_err(ctx, "Failed to allocate action memory %d", ret); 339 mlx5hws_send_abort_new_dep_wqe(queue); 340 return ret; 341 } 342 apply.jump_to_action_stc = 343 rule->action_ste.action_tbl->stc.offset; 344 /* Skip RX/TX based on the dep_wqe init */ 345 ste_attr.rtc_0 = dep_wqe->rtc_0 ? 346 rule->action_ste.action_tbl->rtc_0_id : 0; 347 ste_attr.rtc_1 = dep_wqe->rtc_1 ? 348 rule->action_ste.action_tbl->rtc_1_id : 0; 349 /* Action STEs are written to a specific index last to first */ 350 ste_attr.direct_index = 351 rule->action_ste.ste.offset + action_stes; 352 apply.next_direct_idx = ste_attr.direct_index; 353 } else { 354 apply.next_direct_idx = 0; 355 } 356 357 for (i = total_stes; i-- > 0;) { 358 mlx5hws_action_apply_setter(&apply, setter--, !i && is_jumbo); 359 360 if (i == 0) { 361 /* Handle last match STE. 362 * For hash split / linear lookup RTCs, packets reaching any STE 363 * will always match and perform the specified actions, which 364 * makes the tag irrelevant. 365 */ 366 if (likely(!mlx5hws_matcher_is_insert_by_idx(matcher) && !is_update)) 367 mlx5hws_definer_create_tag(match_param, mt->fc, mt->fc_sz, 368 (u8 *)dep_wqe->wqe_data.action); 369 else if (is_update) 370 hws_rule_update_copy_tag(rule, &dep_wqe->wqe_data, is_jumbo); 371 372 /* Rule has dependent WQEs, match dep_wqe is queued */ 373 if (action_stes || apply.require_dep) 374 break; 375 376 /* Rule has no dependencies, abort dep_wqe and send WQE now */ 377 mlx5hws_send_abort_new_dep_wqe(queue); 378 ste_attr.wqe_tag_is_jumbo = is_jumbo; 379 ste_attr.send_attr.notify_hw = !attr->burst; 380 ste_attr.send_attr.user_data = dep_wqe->user_data; 381 ste_attr.send_attr.rule = dep_wqe->rule; 382 ste_attr.rtc_0 = dep_wqe->rtc_0; 383 ste_attr.rtc_1 = dep_wqe->rtc_1; 384 ste_attr.used_id_rtc_0 = &rule->rtc_0; 385 ste_attr.used_id_rtc_1 = &rule->rtc_1; 386 ste_attr.retry_rtc_0 = dep_wqe->retry_rtc_0; 387 ste_attr.retry_rtc_1 = dep_wqe->retry_rtc_1; 388 ste_attr.direct_index = dep_wqe->direct_index; 389 } else { 390 apply.next_direct_idx = --ste_attr.direct_index; 391 } 392 393 mlx5hws_send_ste(queue, &ste_attr); 394 } 395 396 /* Backup TAG on the rule for deletion and resize info for 397 * moving rules to a new matcher, only after insertion. 398 */ 399 if (!is_update) 400 hws_rule_save_delete_info(rule, &ste_attr); 401 402 hws_rule_save_resize_info(rule, &ste_attr); 403 mlx5hws_send_engine_inc_rule(queue); 404 405 if (!attr->burst) 406 mlx5hws_send_all_dep_wqe(queue); 407 408 return 0; 409} 410 411static void hws_rule_destroy_failed_hws(struct mlx5hws_rule *rule, 412 struct mlx5hws_rule_attr *attr) 413{ 414 struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; 415 struct mlx5hws_send_engine *queue; 416 417 queue = &ctx->send_queue[attr->queue_id]; 418 419 hws_rule_gen_comp(queue, rule, false, 420 attr->user_data, MLX5HWS_RULE_STATUS_DELETED); 421 422 /* Rule failed now we can safely release action STEs */ 423 mlx5hws_rule_free_action_ste(&rule->action_ste); 424 425 /* Perhaps the rule failed updating - release old action STEs as well */ 426 mlx5hws_rule_free_action_ste(&rule->old_action_ste); 427 428 /* Clear complex tag */ 429 hws_rule_clear_delete_info(rule); 430 431 /* Clear info that was saved for resizing */ 432 mlx5hws_rule_clear_resize_info(rule); 433 434 /* If a rule that was indicated as burst (need to trigger HW) has failed 435 * insertion we won't ring the HW as nothing is being written to the WQ. 436 * In such case update the last WQE and ring the HW with that work 437 */ 438 if (attr->burst) 439 return; 440 441 mlx5hws_send_all_dep_wqe(queue); 442 mlx5hws_send_engine_flush_queue(queue); 443} 444 445static int hws_rule_destroy_hws(struct mlx5hws_rule *rule, 446 struct mlx5hws_rule_attr *attr) 447{ 448 bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(rule->matcher->mt); 449 struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; 450 struct mlx5hws_matcher *matcher = rule->matcher; 451 struct mlx5hws_wqe_gta_ctrl_seg wqe_ctrl = {0}; 452 struct mlx5hws_send_ste_attr ste_attr = {0}; 453 struct mlx5hws_send_engine *queue; 454 455 queue = &ctx->send_queue[attr->queue_id]; 456 457 if (unlikely(mlx5hws_send_engine_err(queue))) { 458 hws_rule_destroy_failed_hws(rule, attr); 459 return 0; 460 } 461 462 /* Rule is not completed yet */ 463 if (rule->status == MLX5HWS_RULE_STATUS_CREATING || 464 rule->status == MLX5HWS_RULE_STATUS_UPDATING) 465 return -EBUSY; 466 467 /* Rule failed and doesn't require cleanup */ 468 if (rule->status == MLX5HWS_RULE_STATUS_FAILED) { 469 hws_rule_destroy_failed_hws(rule, attr); 470 return 0; 471 } 472 473 if (rule->skip_delete) { 474 /* Rule shouldn't be deleted in HW. 475 * Generate completion as if write succeeded, and we can 476 * safely release action STEs and clear resize info. 477 */ 478 hws_rule_gen_comp(queue, rule, false, 479 attr->user_data, MLX5HWS_RULE_STATUS_DELETED); 480 481 mlx5hws_rule_free_action_ste(&rule->action_ste); 482 mlx5hws_rule_clear_resize_info(rule); 483 return 0; 484 } 485 486 mlx5hws_send_engine_inc_rule(queue); 487 488 /* Send dependent WQE */ 489 if (!attr->burst) 490 mlx5hws_send_all_dep_wqe(queue); 491 492 rule->status = MLX5HWS_RULE_STATUS_DELETING; 493 494 ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; 495 ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; 496 ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; 497 498 ste_attr.send_attr.rule = rule; 499 ste_attr.send_attr.notify_hw = !attr->burst; 500 ste_attr.send_attr.user_data = attr->user_data; 501 502 ste_attr.rtc_0 = rule->rtc_0; 503 ste_attr.rtc_1 = rule->rtc_1; 504 ste_attr.used_id_rtc_0 = &rule->rtc_0; 505 ste_attr.used_id_rtc_1 = &rule->rtc_1; 506 ste_attr.wqe_ctrl = &wqe_ctrl; 507 ste_attr.wqe_tag_is_jumbo = is_jumbo; 508 ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_DEACTIVATE; 509 if (unlikely(mlx5hws_matcher_is_insert_by_idx(matcher))) 510 ste_attr.direct_index = attr->rule_idx; 511 512 hws_rule_load_delete_info(rule, &ste_attr); 513 mlx5hws_send_ste(queue, &ste_attr); 514 hws_rule_clear_delete_info(rule); 515 516 return 0; 517} 518 519static int hws_rule_enqueue_precheck(struct mlx5hws_rule *rule, 520 struct mlx5hws_rule_attr *attr) 521{ 522 struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; 523 524 if (unlikely(!attr->user_data)) 525 return -EINVAL; 526 527 /* Check if there is room in queue */ 528 if (unlikely(mlx5hws_send_engine_full(&ctx->send_queue[attr->queue_id]))) 529 return -EBUSY; 530 531 return 0; 532} 533 534static int hws_rule_enqueue_precheck_move(struct mlx5hws_rule *rule, 535 struct mlx5hws_rule_attr *attr) 536{ 537 if (unlikely(rule->status != MLX5HWS_RULE_STATUS_CREATED)) 538 return -EINVAL; 539 540 return hws_rule_enqueue_precheck(rule, attr); 541} 542 543static int hws_rule_enqueue_precheck_create(struct mlx5hws_rule *rule, 544 struct mlx5hws_rule_attr *attr) 545{ 546 if (unlikely(mlx5hws_matcher_is_in_resize(rule->matcher))) 547 /* Matcher in resize - new rules are not allowed */ 548 return -EAGAIN; 549 550 return hws_rule_enqueue_precheck(rule, attr); 551} 552 553static int hws_rule_enqueue_precheck_update(struct mlx5hws_rule *rule, 554 struct mlx5hws_rule_attr *attr) 555{ 556 struct mlx5hws_matcher *matcher = rule->matcher; 557 558 if (unlikely(!mlx5hws_matcher_is_resizable(rule->matcher) && 559 !matcher->attr.optimize_using_rule_idx && 560 !mlx5hws_matcher_is_insert_by_idx(matcher))) { 561 return -EOPNOTSUPP; 562 } 563 564 if (unlikely(rule->status != MLX5HWS_RULE_STATUS_CREATED)) 565 return -EBUSY; 566 567 return hws_rule_enqueue_precheck_create(rule, attr); 568} 569 570int mlx5hws_rule_move_hws_remove(struct mlx5hws_rule *rule, 571 void *queue_ptr, 572 void *user_data) 573{ 574 bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(rule->matcher->mt); 575 struct mlx5hws_wqe_gta_ctrl_seg empty_wqe_ctrl = {0}; 576 struct mlx5hws_matcher *matcher = rule->matcher; 577 struct mlx5hws_send_engine *queue = queue_ptr; 578 struct mlx5hws_send_ste_attr ste_attr = {0}; 579 580 mlx5hws_send_all_dep_wqe(queue); 581 582 rule->resize_info->state = MLX5HWS_RULE_RESIZE_STATE_DELETING; 583 584 ste_attr.send_attr.fence = 0; 585 ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; 586 ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; 587 ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; 588 ste_attr.send_attr.rule = rule; 589 ste_attr.send_attr.notify_hw = 1; 590 ste_attr.send_attr.user_data = user_data; 591 ste_attr.rtc_0 = rule->resize_info->rtc_0; 592 ste_attr.rtc_1 = rule->resize_info->rtc_1; 593 ste_attr.used_id_rtc_0 = &rule->resize_info->rtc_0; 594 ste_attr.used_id_rtc_1 = &rule->resize_info->rtc_1; 595 ste_attr.wqe_ctrl = &empty_wqe_ctrl; 596 ste_attr.wqe_tag_is_jumbo = is_jumbo; 597 ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_DEACTIVATE; 598 599 if (unlikely(mlx5hws_matcher_is_insert_by_idx(matcher))) 600 ste_attr.direct_index = rule->resize_info->rule_idx; 601 602 hws_rule_load_delete_info(rule, &ste_attr); 603 mlx5hws_send_ste(queue, &ste_attr); 604 605 return 0; 606} 607 608int mlx5hws_rule_move_hws_add(struct mlx5hws_rule *rule, 609 struct mlx5hws_rule_attr *attr) 610{ 611 bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(rule->matcher->mt); 612 struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; 613 struct mlx5hws_matcher *matcher = rule->matcher; 614 struct mlx5hws_send_ste_attr ste_attr = {0}; 615 struct mlx5hws_send_engine *queue; 616 int ret; 617 618 ret = hws_rule_enqueue_precheck_move(rule, attr); 619 if (unlikely(ret)) 620 return ret; 621 622 queue = &ctx->send_queue[attr->queue_id]; 623 624 ret = mlx5hws_send_engine_err(queue); 625 if (ret) 626 return ret; 627 628 hws_rule_move_init(rule, attr); 629 hws_rule_move_get_rtc(rule, &ste_attr); 630 631 ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; 632 ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; 633 ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; 634 ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; 635 ste_attr.wqe_tag_is_jumbo = is_jumbo; 636 637 ste_attr.send_attr.rule = rule; 638 ste_attr.send_attr.fence = 0; 639 ste_attr.send_attr.notify_hw = !attr->burst; 640 ste_attr.send_attr.user_data = attr->user_data; 641 642 ste_attr.used_id_rtc_0 = &rule->rtc_0; 643 ste_attr.used_id_rtc_1 = &rule->rtc_1; 644 ste_attr.wqe_ctrl = (struct mlx5hws_wqe_gta_ctrl_seg *)rule->resize_info->ctrl_seg; 645 ste_attr.wqe_data = (struct mlx5hws_wqe_gta_data_seg_ste *)rule->resize_info->data_seg; 646 ste_attr.direct_index = mlx5hws_matcher_is_insert_by_idx(matcher) ? 647 attr->rule_idx : 0; 648 649 mlx5hws_send_ste(queue, &ste_attr); 650 mlx5hws_send_engine_inc_rule(queue); 651 652 if (!attr->burst) 653 mlx5hws_send_all_dep_wqe(queue); 654 655 return 0; 656} 657 658static u8 hws_rule_ethertype_to_matcher_ipv(u32 ethertype) 659{ 660 switch (ethertype) { 661 case ETH_P_IP: 662 return MLX5HWS_MATCHER_IPV_4; 663 case ETH_P_IPV6: 664 return MLX5HWS_MATCHER_IPV_6; 665 default: 666 return MLX5HWS_MATCHER_IPV_UNSET; 667 } 668} 669 670static u8 hws_rule_ip_version_to_matcher_ipv(u32 ip_version) 671{ 672 switch (ip_version) { 673 case 4: 674 return MLX5HWS_MATCHER_IPV_4; 675 case 6: 676 return MLX5HWS_MATCHER_IPV_6; 677 default: 678 return MLX5HWS_MATCHER_IPV_UNSET; 679 } 680} 681 682static int hws_rule_check_outer_ip_version(struct mlx5hws_matcher *matcher, 683 u32 *match_param) 684{ 685 struct mlx5hws_context *ctx = matcher->tbl->ctx; 686 u8 outer_ipv_ether = MLX5HWS_MATCHER_IPV_UNSET; 687 u8 outer_ipv_ip = MLX5HWS_MATCHER_IPV_UNSET; 688 u8 outer_ipv, ver; 689 690 if (matcher->matches_outer_ethertype) { 691 ver = MLX5_GET(fte_match_param, match_param, 692 outer_headers.ethertype); 693 outer_ipv_ether = hws_rule_ethertype_to_matcher_ipv(ver); 694 } 695 if (matcher->matches_outer_ip_version) { 696 ver = MLX5_GET(fte_match_param, match_param, 697 outer_headers.ip_version); 698 outer_ipv_ip = hws_rule_ip_version_to_matcher_ipv(ver); 699 } 700 701 if (outer_ipv_ether != MLX5HWS_MATCHER_IPV_UNSET && 702 outer_ipv_ip != MLX5HWS_MATCHER_IPV_UNSET && 703 outer_ipv_ether != outer_ipv_ip) { 704 mlx5hws_err(ctx, "Rule matches on inconsistent outer ethertype and ip version\n"); 705 return -EINVAL; 706 } 707 708 outer_ipv = outer_ipv_ether != MLX5HWS_MATCHER_IPV_UNSET ? 709 outer_ipv_ether : outer_ipv_ip; 710 if (outer_ipv != MLX5HWS_MATCHER_IPV_UNSET && 711 matcher->outer_ip_version != MLX5HWS_MATCHER_IPV_UNSET && 712 outer_ipv != matcher->outer_ip_version) { 713 mlx5hws_err(ctx, "Matcher and rule disagree on outer IP version\n"); 714 return -EINVAL; 715 } 716 matcher->outer_ip_version = outer_ipv; 717 718 return 0; 719} 720 721static int hws_rule_check_inner_ip_version(struct mlx5hws_matcher *matcher, 722 u32 *match_param) 723{ 724 struct mlx5hws_context *ctx = matcher->tbl->ctx; 725 u8 inner_ipv_ether = MLX5HWS_MATCHER_IPV_UNSET; 726 u8 inner_ipv_ip = MLX5HWS_MATCHER_IPV_UNSET; 727 u8 inner_ipv, ver; 728 729 if (matcher->matches_inner_ethertype) { 730 ver = MLX5_GET(fte_match_param, match_param, 731 inner_headers.ethertype); 732 inner_ipv_ether = hws_rule_ethertype_to_matcher_ipv(ver); 733 } 734 if (matcher->matches_inner_ip_version) { 735 ver = MLX5_GET(fte_match_param, match_param, 736 inner_headers.ip_version); 737 inner_ipv_ip = hws_rule_ip_version_to_matcher_ipv(ver); 738 } 739 740 if (inner_ipv_ether != MLX5HWS_MATCHER_IPV_UNSET && 741 inner_ipv_ip != MLX5HWS_MATCHER_IPV_UNSET && 742 inner_ipv_ether != inner_ipv_ip) { 743 mlx5hws_err(ctx, "Rule matches on inconsistent inner ethertype and ip version\n"); 744 return -EINVAL; 745 } 746 747 inner_ipv = inner_ipv_ether != MLX5HWS_MATCHER_IPV_UNSET ? 748 inner_ipv_ether : inner_ipv_ip; 749 if (inner_ipv != MLX5HWS_MATCHER_IPV_UNSET && 750 matcher->inner_ip_version != MLX5HWS_MATCHER_IPV_UNSET && 751 inner_ipv != matcher->inner_ip_version) { 752 mlx5hws_err(ctx, "Matcher and rule disagree on inner IP version\n"); 753 return -EINVAL; 754 } 755 matcher->inner_ip_version = inner_ipv; 756 757 return 0; 758} 759 760static int hws_rule_check_ip_version(struct mlx5hws_matcher *matcher, 761 u32 *match_param) 762{ 763 int ret; 764 765 ret = hws_rule_check_outer_ip_version(matcher, match_param); 766 if (unlikely(ret)) 767 return ret; 768 769 ret = hws_rule_check_inner_ip_version(matcher, match_param); 770 if (unlikely(ret)) 771 return ret; 772 773 return 0; 774} 775 776int mlx5hws_rule_create(struct mlx5hws_matcher *matcher, 777 u8 mt_idx, 778 u32 *match_param, 779 u8 at_idx, 780 struct mlx5hws_rule_action rule_actions[], 781 struct mlx5hws_rule_attr *attr, 782 struct mlx5hws_rule *rule_handle) 783{ 784 int ret; 785 786 ret = hws_rule_check_ip_version(matcher, match_param); 787 if (unlikely(ret)) 788 return ret; 789 790 rule_handle->matcher = matcher; 791 792 ret = hws_rule_enqueue_precheck_create(rule_handle, attr); 793 if (unlikely(ret)) 794 return ret; 795 796 if (unlikely(!(matcher->num_of_mt >= mt_idx) || 797 !(matcher->num_of_at >= at_idx) || 798 !match_param)) { 799 pr_warn("HWS: Invalid rule creation parameters (MTs, ATs or match params)\n"); 800 return -EINVAL; 801 } 802 803 ret = hws_rule_create_hws(rule_handle, 804 attr, 805 mt_idx, 806 match_param, 807 at_idx, 808 rule_actions); 809 810 return ret; 811} 812 813int mlx5hws_rule_destroy(struct mlx5hws_rule *rule, 814 struct mlx5hws_rule_attr *attr) 815{ 816 int ret; 817 818 ret = hws_rule_enqueue_precheck(rule, attr); 819 if (unlikely(ret)) 820 return ret; 821 822 ret = hws_rule_destroy_hws(rule, attr); 823 824 return ret; 825} 826 827int mlx5hws_rule_action_update(struct mlx5hws_rule *rule, 828 u8 at_idx, 829 struct mlx5hws_rule_action rule_actions[], 830 struct mlx5hws_rule_attr *attr) 831{ 832 int ret; 833 834 ret = hws_rule_enqueue_precheck_update(rule, attr); 835 if (unlikely(ret)) 836 return ret; 837 838 ret = hws_rule_create_hws(rule, 839 attr, 840 0, 841 NULL, 842 at_idx, 843 rule_actions); 844 845 return ret; 846}
~/
Read-only file preview.