1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2019 Mellanox Technologies. */ 3 4 #include "dr_types.h" 5 6 int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev, 7 bool other_vport, 8 u16 vport_number, 9 u64 *icm_address_rx, 10 u64 *icm_address_tx) 11 { 12 u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {}; 13 u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {}; 14 int err; 15 16 MLX5_SET(query_esw_vport_context_in, in, opcode, 17 MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT); 18 MLX5_SET(query_esw_vport_context_in, in, other_vport, other_vport); 19 MLX5_SET(query_esw_vport_context_in, in, vport_number, vport_number); 20 21 err = mlx5_cmd_exec_inout(mdev, query_esw_vport_context, in, out); 22 if (err) 23 return err; 24 25 *icm_address_rx = 26 MLX5_GET64(query_esw_vport_context_out, out, 27 esw_vport_context.sw_steering_vport_icm_address_rx); 28 *icm_address_tx = 29 MLX5_GET64(query_esw_vport_context_out, out, 30 esw_vport_context.sw_steering_vport_icm_address_tx); 31 return 0; 32 } 33 34 int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_vport, 35 u16 vport_number, u16 *gvmi) 36 { 37 u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; 38 int out_size; 39 void *out; 40 int err; 41 42 out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); 43 out = kzalloc(out_size, GFP_KERNEL); 44 if (!out) 45 return -ENOMEM; 46 47 MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); 48 MLX5_SET(query_hca_cap_in, in, other_function, other_vport); 49 MLX5_SET(query_hca_cap_in, in, function_id, vport_number); 50 MLX5_SET(query_hca_cap_in, in, op_mod, 51 MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | 52 HCA_CAP_OPMOD_GET_CUR); 53 54 err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out); 55 if (err) { 56 kfree(out); 57 return err; 58 } 59 60 *gvmi = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id); 61 62 kfree(out); 63 return 0; 64 } 65 66 int mlx5dr_cmd_query_esw_caps(struct mlx5_core_dev *mdev, 67 struct mlx5dr_esw_caps *caps) 68 { 69 caps->drop_icm_address_rx = 70 MLX5_CAP64_ESW_FLOWTABLE(mdev, 71 sw_steering_fdb_action_drop_icm_address_rx); 72 caps->drop_icm_address_tx = 73 MLX5_CAP64_ESW_FLOWTABLE(mdev, 74 sw_steering_fdb_action_drop_icm_address_tx); 75 caps->uplink_icm_address_rx = 76 MLX5_CAP64_ESW_FLOWTABLE(mdev, 77 sw_steering_uplink_icm_address_rx); 78 caps->uplink_icm_address_tx = 79 MLX5_CAP64_ESW_FLOWTABLE(mdev, 80 sw_steering_uplink_icm_address_tx); 81 caps->sw_owner = 82 MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, 83 sw_owner); 84 85 return 0; 86 } 87 88 int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev, 89 struct mlx5dr_cmd_caps *caps) 90 { 91 caps->prio_tag_required = MLX5_CAP_GEN(mdev, prio_tag_required); 92 caps->eswitch_manager = MLX5_CAP_GEN(mdev, eswitch_manager); 93 caps->gvmi = MLX5_CAP_GEN(mdev, vhca_id); 94 caps->flex_protocols = MLX5_CAP_GEN(mdev, flex_parser_protocols); 95 96 if (mlx5dr_matcher_supp_flex_parser_icmp_v4(caps)) { 97 caps->flex_parser_id_icmp_dw0 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw0); 98 caps->flex_parser_id_icmp_dw1 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw1); 99 } 100 101 if (mlx5dr_matcher_supp_flex_parser_icmp_v6(caps)) { 102 caps->flex_parser_id_icmpv6_dw0 = 103 MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw0); 104 caps->flex_parser_id_icmpv6_dw1 = 105 MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw1); 106 } 107 108 caps->nic_rx_drop_address = 109 MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_rx_action_drop_icm_address); 110 caps->nic_tx_drop_address = 111 MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_drop_icm_address); 112 caps->nic_tx_allow_address = 113 MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_allow_icm_address); 114 115 caps->rx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, sw_owner); 116 caps->max_ft_level = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, max_ft_level); 117 118 caps->tx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_TX(mdev, sw_owner); 119 120 caps->log_icm_size = MLX5_CAP_DEV_MEM(mdev, log_steering_sw_icm_size); 121 caps->hdr_modify_icm_addr = 122 MLX5_CAP64_DEV_MEM(mdev, header_modify_sw_icm_start_address); 123 124 caps->roce_min_src_udp = MLX5_CAP_ROCE(mdev, r_roce_min_src_udp_port); 125 126 return 0; 127 } 128 129 int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev, 130 enum fs_flow_table_type type, 131 u32 table_id, 132 struct mlx5dr_cmd_query_flow_table_details *output) 133 { 134 u32 out[MLX5_ST_SZ_DW(query_flow_table_out)] = {}; 135 u32 in[MLX5_ST_SZ_DW(query_flow_table_in)] = {}; 136 int err; 137 138 MLX5_SET(query_flow_table_in, in, opcode, 139 MLX5_CMD_OP_QUERY_FLOW_TABLE); 140 141 MLX5_SET(query_flow_table_in, in, table_type, type); 142 MLX5_SET(query_flow_table_in, in, table_id, table_id); 143 144 err = mlx5_cmd_exec_inout(dev, query_flow_table, in, out); 145 if (err) 146 return err; 147 148 output->status = MLX5_GET(query_flow_table_out, out, status); 149 output->level = MLX5_GET(query_flow_table_out, out, flow_table_context.level); 150 151 output->sw_owner_icm_root_1 = MLX5_GET64(query_flow_table_out, out, 152 flow_table_context.sw_owner_icm_root_1); 153 output->sw_owner_icm_root_0 = MLX5_GET64(query_flow_table_out, out, 154 flow_table_context.sw_owner_icm_root_0); 155 156 return 0; 157 } 158 159 int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev) 160 { 161 u32 in[MLX5_ST_SZ_DW(sync_steering_in)] = {}; 162 163 MLX5_SET(sync_steering_in, in, opcode, MLX5_CMD_OP_SYNC_STEERING); 164 165 return mlx5_cmd_exec_in(mdev, sync_steering, in); 166 } 167 168 int mlx5dr_cmd_set_fte_modify_and_vport(struct mlx5_core_dev *mdev, 169 u32 table_type, 170 u32 table_id, 171 u32 group_id, 172 u32 modify_header_id, 173 u32 vport_id) 174 { 175 u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {}; 176 void *in_flow_context; 177 unsigned int inlen; 178 void *in_dests; 179 u32 *in; 180 int err; 181 182 inlen = MLX5_ST_SZ_BYTES(set_fte_in) + 183 1 * MLX5_ST_SZ_BYTES(dest_format_struct); /* One destination only */ 184 185 in = kvzalloc(inlen, GFP_KERNEL); 186 if (!in) 187 return -ENOMEM; 188 189 MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); 190 MLX5_SET(set_fte_in, in, table_type, table_type); 191 MLX5_SET(set_fte_in, in, table_id, table_id); 192 193 in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); 194 MLX5_SET(flow_context, in_flow_context, group_id, group_id); 195 MLX5_SET(flow_context, in_flow_context, modify_header_id, modify_header_id); 196 MLX5_SET(flow_context, in_flow_context, destination_list_size, 1); 197 MLX5_SET(flow_context, in_flow_context, action, 198 MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 199 MLX5_FLOW_CONTEXT_ACTION_MOD_HDR); 200 201 in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination); 202 MLX5_SET(dest_format_struct, in_dests, destination_type, 203 MLX5_FLOW_DESTINATION_TYPE_VPORT); 204 MLX5_SET(dest_format_struct, in_dests, destination_id, vport_id); 205 206 err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); 207 kvfree(in); 208 209 return err; 210 } 211 212 int mlx5dr_cmd_del_flow_table_entry(struct mlx5_core_dev *mdev, 213 u32 table_type, 214 u32 table_id) 215 { 216 u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {}; 217 218 MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); 219 MLX5_SET(delete_fte_in, in, table_type, table_type); 220 MLX5_SET(delete_fte_in, in, table_id, table_id); 221 222 return mlx5_cmd_exec_in(mdev, delete_fte, in); 223 } 224 225 int mlx5dr_cmd_alloc_modify_header(struct mlx5_core_dev *mdev, 226 u32 table_type, 227 u8 num_of_actions, 228 u64 *actions, 229 u32 *modify_header_id) 230 { 231 u32 out[MLX5_ST_SZ_DW(alloc_modify_header_context_out)] = {}; 232 void *p_actions; 233 u32 inlen; 234 u32 *in; 235 int err; 236 237 inlen = MLX5_ST_SZ_BYTES(alloc_modify_header_context_in) + 238 num_of_actions * sizeof(u64); 239 in = kvzalloc(inlen, GFP_KERNEL); 240 if (!in) 241 return -ENOMEM; 242 243 MLX5_SET(alloc_modify_header_context_in, in, opcode, 244 MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT); 245 MLX5_SET(alloc_modify_header_context_in, in, table_type, table_type); 246 MLX5_SET(alloc_modify_header_context_in, in, num_of_actions, num_of_actions); 247 p_actions = MLX5_ADDR_OF(alloc_modify_header_context_in, in, actions); 248 memcpy(p_actions, actions, num_of_actions * sizeof(u64)); 249 250 err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); 251 if (err) 252 goto out; 253 254 *modify_header_id = MLX5_GET(alloc_modify_header_context_out, out, 255 modify_header_id); 256 out: 257 kvfree(in); 258 return err; 259 } 260 261 int mlx5dr_cmd_dealloc_modify_header(struct mlx5_core_dev *mdev, 262 u32 modify_header_id) 263 { 264 u32 in[MLX5_ST_SZ_DW(dealloc_modify_header_context_in)] = {}; 265 266 MLX5_SET(dealloc_modify_header_context_in, in, opcode, 267 MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT); 268 MLX5_SET(dealloc_modify_header_context_in, in, modify_header_id, 269 modify_header_id); 270 271 return mlx5_cmd_exec_in(mdev, dealloc_modify_header_context, in); 272 } 273 274 int mlx5dr_cmd_create_empty_flow_group(struct mlx5_core_dev *mdev, 275 u32 table_type, 276 u32 table_id, 277 u32 *group_id) 278 { 279 u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {}; 280 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 281 u32 *in; 282 int err; 283 284 in = kzalloc(inlen, GFP_KERNEL); 285 if (!in) 286 return -ENOMEM; 287 288 MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP); 289 MLX5_SET(create_flow_group_in, in, table_type, table_type); 290 MLX5_SET(create_flow_group_in, in, table_id, table_id); 291 292 err = mlx5_cmd_exec_inout(mdev, create_flow_group, in, out); 293 if (err) 294 goto out; 295 296 *group_id = MLX5_GET(create_flow_group_out, out, group_id); 297 298 out: 299 kfree(in); 300 return err; 301 } 302 303 int mlx5dr_cmd_destroy_flow_group(struct mlx5_core_dev *mdev, 304 u32 table_type, 305 u32 table_id, 306 u32 group_id) 307 { 308 u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {}; 309 310 MLX5_SET(destroy_flow_group_in, in, opcode, 311 MLX5_CMD_OP_DESTROY_FLOW_GROUP); 312 MLX5_SET(destroy_flow_group_in, in, table_type, table_type); 313 MLX5_SET(destroy_flow_group_in, in, table_id, table_id); 314 MLX5_SET(destroy_flow_group_in, in, group_id, group_id); 315 316 return mlx5_cmd_exec_in(mdev, destroy_flow_group, in); 317 } 318 319 int mlx5dr_cmd_create_flow_table(struct mlx5_core_dev *mdev, 320 struct mlx5dr_cmd_create_flow_table_attr *attr, 321 u64 *fdb_rx_icm_addr, 322 u32 *table_id) 323 { 324 u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {}; 325 u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {}; 326 void *ft_mdev; 327 int err; 328 329 MLX5_SET(create_flow_table_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_TABLE); 330 MLX5_SET(create_flow_table_in, in, table_type, attr->table_type); 331 332 ft_mdev = MLX5_ADDR_OF(create_flow_table_in, in, flow_table_context); 333 MLX5_SET(flow_table_context, ft_mdev, termination_table, attr->term_tbl); 334 MLX5_SET(flow_table_context, ft_mdev, sw_owner, attr->sw_owner); 335 MLX5_SET(flow_table_context, ft_mdev, level, attr->level); 336 337 if (attr->sw_owner) { 338 /* icm_addr_0 used for FDB RX / NIC TX / NIC_RX 339 * icm_addr_1 used for FDB TX 340 */ 341 if (attr->table_type == MLX5_FLOW_TABLE_TYPE_NIC_RX) { 342 MLX5_SET64(flow_table_context, ft_mdev, 343 sw_owner_icm_root_0, attr->icm_addr_rx); 344 } else if (attr->table_type == MLX5_FLOW_TABLE_TYPE_NIC_TX) { 345 MLX5_SET64(flow_table_context, ft_mdev, 346 sw_owner_icm_root_0, attr->icm_addr_tx); 347 } else if (attr->table_type == MLX5_FLOW_TABLE_TYPE_FDB) { 348 MLX5_SET64(flow_table_context, ft_mdev, 349 sw_owner_icm_root_0, attr->icm_addr_rx); 350 MLX5_SET64(flow_table_context, ft_mdev, 351 sw_owner_icm_root_1, attr->icm_addr_tx); 352 } 353 } 354 355 MLX5_SET(create_flow_table_in, in, flow_table_context.decap_en, 356 attr->decap_en); 357 MLX5_SET(create_flow_table_in, in, flow_table_context.reformat_en, 358 attr->reformat_en); 359 360 err = mlx5_cmd_exec_inout(mdev, create_flow_table, in, out); 361 if (err) 362 return err; 363 364 *table_id = MLX5_GET(create_flow_table_out, out, table_id); 365 if (!attr->sw_owner && attr->table_type == MLX5_FLOW_TABLE_TYPE_FDB && 366 fdb_rx_icm_addr) 367 *fdb_rx_icm_addr = 368 (u64)MLX5_GET(create_flow_table_out, out, icm_address_31_0) | 369 (u64)MLX5_GET(create_flow_table_out, out, icm_address_39_32) << 32 | 370 (u64)MLX5_GET(create_flow_table_out, out, icm_address_63_40) << 40; 371 372 return 0; 373 } 374 375 int mlx5dr_cmd_destroy_flow_table(struct mlx5_core_dev *mdev, 376 u32 table_id, 377 u32 table_type) 378 { 379 u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {}; 380 381 MLX5_SET(destroy_flow_table_in, in, opcode, 382 MLX5_CMD_OP_DESTROY_FLOW_TABLE); 383 MLX5_SET(destroy_flow_table_in, in, table_type, table_type); 384 MLX5_SET(destroy_flow_table_in, in, table_id, table_id); 385 386 return mlx5_cmd_exec_in(mdev, destroy_flow_table, in); 387 } 388 389 int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev, 390 enum mlx5_reformat_ctx_type rt, 391 size_t reformat_size, 392 void *reformat_data, 393 u32 *reformat_id) 394 { 395 u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)] = {}; 396 size_t inlen, cmd_data_sz, cmd_total_sz; 397 void *prctx; 398 void *pdata; 399 void *in; 400 int err; 401 402 cmd_total_sz = MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in); 403 cmd_data_sz = MLX5_FLD_SZ_BYTES(alloc_packet_reformat_context_in, 404 packet_reformat_context.reformat_data); 405 inlen = ALIGN(cmd_total_sz + reformat_size - cmd_data_sz, 4); 406 in = kvzalloc(inlen, GFP_KERNEL); 407 if (!in) 408 return -ENOMEM; 409 410 MLX5_SET(alloc_packet_reformat_context_in, in, opcode, 411 MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT); 412 413 prctx = MLX5_ADDR_OF(alloc_packet_reformat_context_in, in, packet_reformat_context); 414 pdata = MLX5_ADDR_OF(packet_reformat_context_in, prctx, reformat_data); 415 416 MLX5_SET(packet_reformat_context_in, prctx, reformat_type, rt); 417 MLX5_SET(packet_reformat_context_in, prctx, reformat_data_size, reformat_size); 418 memcpy(pdata, reformat_data, reformat_size); 419 420 err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); 421 if (err) 422 return err; 423 424 *reformat_id = MLX5_GET(alloc_packet_reformat_context_out, out, packet_reformat_id); 425 kvfree(in); 426 427 return err; 428 } 429 430 void mlx5dr_cmd_destroy_reformat_ctx(struct mlx5_core_dev *mdev, 431 u32 reformat_id) 432 { 433 u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)] = {}; 434 435 MLX5_SET(dealloc_packet_reformat_context_in, in, opcode, 436 MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT); 437 MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id, 438 reformat_id); 439 440 mlx5_cmd_exec_in(mdev, dealloc_packet_reformat_context, in); 441 } 442 443 int mlx5dr_cmd_query_gid(struct mlx5_core_dev *mdev, u8 vhca_port_num, 444 u16 index, struct mlx5dr_cmd_gid_attr *attr) 445 { 446 u32 out[MLX5_ST_SZ_DW(query_roce_address_out)] = {}; 447 u32 in[MLX5_ST_SZ_DW(query_roce_address_in)] = {}; 448 int err; 449 450 MLX5_SET(query_roce_address_in, in, opcode, 451 MLX5_CMD_OP_QUERY_ROCE_ADDRESS); 452 453 MLX5_SET(query_roce_address_in, in, roce_address_index, index); 454 MLX5_SET(query_roce_address_in, in, vhca_port_num, vhca_port_num); 455 456 err = mlx5_cmd_exec_inout(mdev, query_roce_address, in, out); 457 if (err) 458 return err; 459 460 memcpy(&attr->gid, 461 MLX5_ADDR_OF(query_roce_address_out, 462 out, roce_address.source_l3_address), 463 sizeof(attr->gid)); 464 memcpy(attr->mac, 465 MLX5_ADDR_OF(query_roce_address_out, out, 466 roce_address.source_mac_47_32), 467 sizeof(attr->mac)); 468 469 if (MLX5_GET(query_roce_address_out, out, 470 roce_address.roce_version) == MLX5_ROCE_VERSION_2) 471 attr->roce_ver = MLX5_ROCE_VERSION_2; 472 else 473 attr->roce_ver = MLX5_ROCE_VERSION_1; 474 475 return 0; 476 } 477 478 static int mlx5dr_cmd_set_extended_dest(struct mlx5_core_dev *dev, 479 struct mlx5dr_cmd_fte_info *fte, 480 bool *extended_dest) 481 { 482 int fw_log_max_fdb_encap_uplink = MLX5_CAP_ESW(dev, log_max_fdb_encap_uplink); 483 int num_fwd_destinations = 0; 484 int num_encap = 0; 485 int i; 486 487 *extended_dest = false; 488 if (!(fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST)) 489 return 0; 490 for (i = 0; i < fte->dests_size; i++) { 491 if (fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_COUNTER) 492 continue; 493 if (fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_VPORT && 494 fte->dest_arr[i].vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID) 495 num_encap++; 496 num_fwd_destinations++; 497 } 498 499 if (num_fwd_destinations > 1 && num_encap > 0) 500 *extended_dest = true; 501 502 if (*extended_dest && !fw_log_max_fdb_encap_uplink) { 503 mlx5_core_warn(dev, "FW does not support extended destination"); 504 return -EOPNOTSUPP; 505 } 506 if (num_encap > (1 << fw_log_max_fdb_encap_uplink)) { 507 mlx5_core_warn(dev, "FW does not support more than %d encaps", 508 1 << fw_log_max_fdb_encap_uplink); 509 return -EOPNOTSUPP; 510 } 511 512 return 0; 513 } 514 515 int mlx5dr_cmd_set_fte(struct mlx5_core_dev *dev, 516 int opmod, int modify_mask, 517 struct mlx5dr_cmd_ft_info *ft, 518 u32 group_id, 519 struct mlx5dr_cmd_fte_info *fte) 520 { 521 u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {}; 522 void *in_flow_context, *vlan; 523 bool extended_dest = false; 524 void *in_match_value; 525 unsigned int inlen; 526 int dst_cnt_size; 527 void *in_dests; 528 u32 *in; 529 int err; 530 int i; 531 532 if (mlx5dr_cmd_set_extended_dest(dev, fte, &extended_dest)) 533 return -EOPNOTSUPP; 534 535 if (!extended_dest) 536 dst_cnt_size = MLX5_ST_SZ_BYTES(dest_format_struct); 537 else 538 dst_cnt_size = MLX5_ST_SZ_BYTES(extended_dest_format); 539 540 inlen = MLX5_ST_SZ_BYTES(set_fte_in) + fte->dests_size * dst_cnt_size; 541 in = kvzalloc(inlen, GFP_KERNEL); 542 if (!in) 543 return -ENOMEM; 544 545 MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); 546 MLX5_SET(set_fte_in, in, op_mod, opmod); 547 MLX5_SET(set_fte_in, in, modify_enable_mask, modify_mask); 548 MLX5_SET(set_fte_in, in, table_type, ft->type); 549 MLX5_SET(set_fte_in, in, table_id, ft->id); 550 MLX5_SET(set_fte_in, in, flow_index, fte->index); 551 if (ft->vport) { 552 MLX5_SET(set_fte_in, in, vport_number, ft->vport); 553 MLX5_SET(set_fte_in, in, other_vport, 1); 554 } 555 556 in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); 557 MLX5_SET(flow_context, in_flow_context, group_id, group_id); 558 559 MLX5_SET(flow_context, in_flow_context, flow_tag, 560 fte->flow_context.flow_tag); 561 MLX5_SET(flow_context, in_flow_context, flow_source, 562 fte->flow_context.flow_source); 563 564 MLX5_SET(flow_context, in_flow_context, extended_destination, 565 extended_dest); 566 if (extended_dest) { 567 u32 action; 568 569 action = fte->action.action & 570 ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; 571 MLX5_SET(flow_context, in_flow_context, action, action); 572 } else { 573 MLX5_SET(flow_context, in_flow_context, action, 574 fte->action.action); 575 if (fte->action.pkt_reformat) 576 MLX5_SET(flow_context, in_flow_context, packet_reformat_id, 577 fte->action.pkt_reformat->id); 578 } 579 if (fte->action.modify_hdr) 580 MLX5_SET(flow_context, in_flow_context, modify_header_id, 581 fte->action.modify_hdr->id); 582 583 vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan); 584 585 MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[0].ethtype); 586 MLX5_SET(vlan, vlan, vid, fte->action.vlan[0].vid); 587 MLX5_SET(vlan, vlan, prio, fte->action.vlan[0].prio); 588 589 vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan_2); 590 591 MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[1].ethtype); 592 MLX5_SET(vlan, vlan, vid, fte->action.vlan[1].vid); 593 MLX5_SET(vlan, vlan, prio, fte->action.vlan[1].prio); 594 595 in_match_value = MLX5_ADDR_OF(flow_context, in_flow_context, 596 match_value); 597 memcpy(in_match_value, fte->val, sizeof(u32) * MLX5_ST_SZ_DW_MATCH_PARAM); 598 599 in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination); 600 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { 601 int list_size = 0; 602 603 for (i = 0; i < fte->dests_size; i++) { 604 unsigned int id, type = fte->dest_arr[i].type; 605 606 if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER) 607 continue; 608 609 switch (type) { 610 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: 611 id = fte->dest_arr[i].ft_num; 612 type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 613 break; 614 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: 615 id = fte->dest_arr[i].ft_id; 616 break; 617 case MLX5_FLOW_DESTINATION_TYPE_VPORT: 618 id = fte->dest_arr[i].vport.num; 619 MLX5_SET(dest_format_struct, in_dests, 620 destination_eswitch_owner_vhca_id_valid, 621 !!(fte->dest_arr[i].vport.flags & 622 MLX5_FLOW_DEST_VPORT_VHCA_ID)); 623 MLX5_SET(dest_format_struct, in_dests, 624 destination_eswitch_owner_vhca_id, 625 fte->dest_arr[i].vport.vhca_id); 626 if (extended_dest && (fte->dest_arr[i].vport.flags & 627 MLX5_FLOW_DEST_VPORT_REFORMAT_ID)) { 628 MLX5_SET(dest_format_struct, in_dests, 629 packet_reformat, 630 !!(fte->dest_arr[i].vport.flags & 631 MLX5_FLOW_DEST_VPORT_REFORMAT_ID)); 632 MLX5_SET(extended_dest_format, in_dests, 633 packet_reformat_id, 634 fte->dest_arr[i].vport.reformat_id); 635 } 636 break; 637 default: 638 id = fte->dest_arr[i].tir_num; 639 } 640 641 MLX5_SET(dest_format_struct, in_dests, destination_type, 642 type); 643 MLX5_SET(dest_format_struct, in_dests, destination_id, id); 644 in_dests += dst_cnt_size; 645 list_size++; 646 } 647 648 MLX5_SET(flow_context, in_flow_context, destination_list_size, 649 list_size); 650 } 651 652 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 653 int max_list_size = BIT(MLX5_CAP_FLOWTABLE_TYPE(dev, 654 log_max_flow_counter, 655 ft->type)); 656 int list_size = 0; 657 658 for (i = 0; i < fte->dests_size; i++) { 659 if (fte->dest_arr[i].type != 660 MLX5_FLOW_DESTINATION_TYPE_COUNTER) 661 continue; 662 663 MLX5_SET(flow_counter_list, in_dests, flow_counter_id, 664 fte->dest_arr[i].counter_id); 665 in_dests += dst_cnt_size; 666 list_size++; 667 } 668 if (list_size > max_list_size) { 669 err = -EINVAL; 670 goto err_out; 671 } 672 673 MLX5_SET(flow_context, in_flow_context, flow_counter_list_size, 674 list_size); 675 } 676 677 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); 678 err_out: 679 kvfree(in); 680 return err; 681 } 682