| // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
| /* Copyright (c) 2019 Mellanox Technologies. */ |
| |
| #include "dr_types.h" |
| |
| int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev, |
| bool other_vport, |
| u16 vport_number, |
| u64 *icm_address_rx, |
| u64 *icm_address_tx) |
| { |
| u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {}; |
| u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {}; |
| int err; |
| |
| MLX5_SET(query_esw_vport_context_in, in, opcode, |
| MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT); |
| MLX5_SET(query_esw_vport_context_in, in, other_vport, other_vport); |
| MLX5_SET(query_esw_vport_context_in, in, vport_number, vport_number); |
| |
| err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
| if (err) |
| return err; |
| |
| *icm_address_rx = |
| MLX5_GET64(query_esw_vport_context_out, out, |
| esw_vport_context.sw_steering_vport_icm_address_rx); |
| *icm_address_tx = |
| MLX5_GET64(query_esw_vport_context_out, out, |
| esw_vport_context.sw_steering_vport_icm_address_tx); |
| return 0; |
| } |
| |
| int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_vport, |
| u16 vport_number, u16 *gvmi) |
| { |
| u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; |
| int out_size; |
| void *out; |
| int err; |
| |
| out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); |
| out = kzalloc(out_size, GFP_KERNEL); |
| if (!out) |
| return -ENOMEM; |
| |
| MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); |
| MLX5_SET(query_hca_cap_in, in, other_function, other_vport); |
| MLX5_SET(query_hca_cap_in, in, function_id, vport_number); |
| MLX5_SET(query_hca_cap_in, in, op_mod, |
| MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | |
| HCA_CAP_OPMOD_GET_CUR); |
| |
| err = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); |
| if (err) { |
| kfree(out); |
| return err; |
| } |
| |
| *gvmi = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id); |
| |
| kfree(out); |
| return 0; |
| } |
| |
| int mlx5dr_cmd_query_esw_caps(struct mlx5_core_dev *mdev, |
| struct mlx5dr_esw_caps *caps) |
| { |
| caps->drop_icm_address_rx = |
| MLX5_CAP64_ESW_FLOWTABLE(mdev, |
| sw_steering_fdb_action_drop_icm_address_rx); |
| caps->drop_icm_address_tx = |
| MLX5_CAP64_ESW_FLOWTABLE(mdev, |
| sw_steering_fdb_action_drop_icm_address_tx); |
| caps->uplink_icm_address_rx = |
| MLX5_CAP64_ESW_FLOWTABLE(mdev, |
| sw_steering_uplink_icm_address_rx); |
| caps->uplink_icm_address_tx = |
| MLX5_CAP64_ESW_FLOWTABLE(mdev, |
| sw_steering_uplink_icm_address_tx); |
| caps->sw_owner = |
| MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, |
| sw_owner); |
| |
| return 0; |
| } |
| |
| int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev, |
| struct mlx5dr_cmd_caps *caps) |
| { |
| caps->prio_tag_required = MLX5_CAP_GEN(mdev, prio_tag_required); |
| caps->eswitch_manager = MLX5_CAP_GEN(mdev, eswitch_manager); |
| caps->gvmi = MLX5_CAP_GEN(mdev, vhca_id); |
| caps->flex_protocols = MLX5_CAP_GEN(mdev, flex_parser_protocols); |
| |
| if (mlx5dr_matcher_supp_flex_parser_icmp_v4(caps)) { |
| caps->flex_parser_id_icmp_dw0 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw0); |
| caps->flex_parser_id_icmp_dw1 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw1); |
| } |
| |
| if (mlx5dr_matcher_supp_flex_parser_icmp_v6(caps)) { |
| caps->flex_parser_id_icmpv6_dw0 = |
| MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw0); |
| caps->flex_parser_id_icmpv6_dw1 = |
| MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw1); |
| } |
| |
| caps->nic_rx_drop_address = |
| MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_rx_action_drop_icm_address); |
| caps->nic_tx_drop_address = |
| MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_drop_icm_address); |
| caps->nic_tx_allow_address = |
| MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_allow_icm_address); |
| |
| caps->rx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, sw_owner); |
| caps->max_ft_level = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, max_ft_level); |
| |
| caps->tx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_TX(mdev, sw_owner); |
| |
| caps->log_icm_size = MLX5_CAP_DEV_MEM(mdev, log_steering_sw_icm_size); |
| caps->hdr_modify_icm_addr = |
| MLX5_CAP64_DEV_MEM(mdev, header_modify_sw_icm_start_address); |
| |
| caps->roce_min_src_udp = MLX5_CAP_ROCE(mdev, r_roce_min_src_udp_port); |
| |
| return 0; |
| } |
| |
| int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev, |
| enum fs_flow_table_type type, |
| u32 table_id, |
| struct mlx5dr_cmd_query_flow_table_details *output) |
| { |
| u32 out[MLX5_ST_SZ_DW(query_flow_table_out)] = {}; |
| u32 in[MLX5_ST_SZ_DW(query_flow_table_in)] = {}; |
| int err; |
| |
| MLX5_SET(query_flow_table_in, in, opcode, |
| MLX5_CMD_OP_QUERY_FLOW_TABLE); |
| |
| MLX5_SET(query_flow_table_in, in, table_type, type); |
| MLX5_SET(query_flow_table_in, in, table_id, table_id); |
| |
| err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); |
| if (err) |
| return err; |
| |
| output->status = MLX5_GET(query_flow_table_out, out, status); |
| output->level = MLX5_GET(query_flow_table_out, out, flow_table_context.level); |
| |
| output->sw_owner_icm_root_1 = MLX5_GET64(query_flow_table_out, out, |
| flow_table_context.sw_owner_icm_root_1); |
| output->sw_owner_icm_root_0 = MLX5_GET64(query_flow_table_out, out, |
| flow_table_context.sw_owner_icm_root_0); |
| |
| return 0; |
| } |
| |
| int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev) |
| { |
| u32 out[MLX5_ST_SZ_DW(sync_steering_out)] = {}; |
| u32 in[MLX5_ST_SZ_DW(sync_steering_in)] = {}; |
| |
| MLX5_SET(sync_steering_in, in, opcode, MLX5_CMD_OP_SYNC_STEERING); |
| |
| return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
| } |
| |
| int mlx5dr_cmd_set_fte_modify_and_vport(struct mlx5_core_dev *mdev, |
| u32 table_type, |
| u32 table_id, |
| u32 group_id, |
| u32 modify_header_id, |
| u32 vport_id) |
| { |
| u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {}; |
| void *in_flow_context; |
| unsigned int inlen; |
| void *in_dests; |
| u32 *in; |
| int err; |
| |
| inlen = MLX5_ST_SZ_BYTES(set_fte_in) + |
| 1 * MLX5_ST_SZ_BYTES(dest_format_struct); /* One destination only */ |
| |
| in = kvzalloc(inlen, GFP_KERNEL); |
| if (!in) |
| return -ENOMEM; |
| |
| MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); |
| MLX5_SET(set_fte_in, in, table_type, table_type); |
| MLX5_SET(set_fte_in, in, table_id, table_id); |
| |
| in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); |
| MLX5_SET(flow_context, in_flow_context, group_id, group_id); |
| MLX5_SET(flow_context, in_flow_context, modify_header_id, modify_header_id); |
| MLX5_SET(flow_context, in_flow_context, destination_list_size, 1); |
| MLX5_SET(flow_context, in_flow_context, action, |
| MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | |
| MLX5_FLOW_CONTEXT_ACTION_MOD_HDR); |
| |
| in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination); |
| MLX5_SET(dest_format_struct, in_dests, destination_type, |
| MLX5_FLOW_DESTINATION_TYPE_VPORT); |
| MLX5_SET(dest_format_struct, in_dests, destination_id, vport_id); |
| |
| err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); |
| kvfree(in); |
| |
| return err; |
| } |
| |
| int mlx5dr_cmd_del_flow_table_entry(struct mlx5_core_dev *mdev, |
| u32 table_type, |
| u32 table_id) |
| { |
| u32 out[MLX5_ST_SZ_DW(delete_fte_out)] = {}; |
| u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {}; |
| |
| MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); |
| MLX5_SET(delete_fte_in, in, table_type, table_type); |
| MLX5_SET(delete_fte_in, in, table_id, table_id); |
| |
| return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
| } |
| |
| int mlx5dr_cmd_alloc_modify_header(struct mlx5_core_dev *mdev, |
| u32 table_type, |
| u8 num_of_actions, |
| u64 *actions, |
| u32 *modify_header_id) |
| { |
| u32 out[MLX5_ST_SZ_DW(alloc_modify_header_context_out)] = {}; |
| void *p_actions; |
| u32 inlen; |
| u32 *in; |
| int err; |
| |
| inlen = MLX5_ST_SZ_BYTES(alloc_modify_header_context_in) + |
| num_of_actions * sizeof(u64); |
| in = kvzalloc(inlen, GFP_KERNEL); |
| if (!in) |
| return -ENOMEM; |
| |
| MLX5_SET(alloc_modify_header_context_in, in, opcode, |
| MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT); |
| MLX5_SET(alloc_modify_header_context_in, in, table_type, table_type); |
| MLX5_SET(alloc_modify_header_context_in, in, num_of_actions, num_of_actions); |
| p_actions = MLX5_ADDR_OF(alloc_modify_header_context_in, in, actions); |
| memcpy(p_actions, actions, num_of_actions * sizeof(u64)); |
| |
| err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); |
| if (err) |
| goto out; |
| |
| *modify_header_id = MLX5_GET(alloc_modify_header_context_out, out, |
| modify_header_id); |
| out: |
| kvfree(in); |
| return err; |
| } |
| |
| int mlx5dr_cmd_dealloc_modify_header(struct mlx5_core_dev *mdev, |
| u32 modify_header_id) |
| { |
| u32 out[MLX5_ST_SZ_DW(dealloc_modify_header_context_out)] = {}; |
| u32 in[MLX5_ST_SZ_DW(dealloc_modify_header_context_in)] = {}; |
| |
| MLX5_SET(dealloc_modify_header_context_in, in, opcode, |
| MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT); |
| MLX5_SET(dealloc_modify_header_context_in, in, modify_header_id, |
| modify_header_id); |
| |
| return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
| } |
| |
| int mlx5dr_cmd_create_empty_flow_group(struct mlx5_core_dev *mdev, |
| u32 table_type, |
| u32 table_id, |
| u32 *group_id) |
| { |
| u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {}; |
| int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); |
| u32 *in; |
| int err; |
| |
| in = kzalloc(inlen, GFP_KERNEL); |
| if (!in) |
| return -ENOMEM; |
| |
| MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP); |
| MLX5_SET(create_flow_group_in, in, table_type, table_type); |
| MLX5_SET(create_flow_group_in, in, table_id, table_id); |
| |
| err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); |
| if (err) |
| goto out; |
| |
| *group_id = MLX5_GET(create_flow_group_out, out, group_id); |
| |
| out: |
| kfree(in); |
| return err; |
| } |
| |
| int mlx5dr_cmd_destroy_flow_group(struct mlx5_core_dev *mdev, |
| u32 table_type, |
| u32 table_id, |
| u32 group_id) |
| { |
| u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {}; |
| u32 out[MLX5_ST_SZ_DW(destroy_flow_group_out)] = {}; |
| |
| MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_DESTROY_FLOW_GROUP); |
| MLX5_SET(destroy_flow_group_in, in, table_type, table_type); |
| MLX5_SET(destroy_flow_group_in, in, table_id, table_id); |
| MLX5_SET(destroy_flow_group_in, in, group_id, group_id); |
| |
| return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
| } |
| |
| int mlx5dr_cmd_create_flow_table(struct mlx5_core_dev *mdev, |
| u32 table_type, |
| u64 icm_addr_rx, |
| u64 icm_addr_tx, |
| u8 level, |
| bool sw_owner, |
| bool term_tbl, |
| u64 *fdb_rx_icm_addr, |
| u32 *table_id) |
| { |
| u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {}; |
| u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {}; |
| void *ft_mdev; |
| int err; |
| |
| MLX5_SET(create_flow_table_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_TABLE); |
| MLX5_SET(create_flow_table_in, in, table_type, table_type); |
| |
| ft_mdev = MLX5_ADDR_OF(create_flow_table_in, in, flow_table_context); |
| MLX5_SET(flow_table_context, ft_mdev, termination_table, term_tbl); |
| MLX5_SET(flow_table_context, ft_mdev, sw_owner, sw_owner); |
| MLX5_SET(flow_table_context, ft_mdev, level, level); |
| |
| if (sw_owner) { |
| /* icm_addr_0 used for FDB RX / NIC TX / NIC_RX |
| * icm_addr_1 used for FDB TX |
| */ |
| if (table_type == MLX5_FLOW_TABLE_TYPE_NIC_RX) { |
| MLX5_SET64(flow_table_context, ft_mdev, |
| sw_owner_icm_root_0, icm_addr_rx); |
| } else if (table_type == MLX5_FLOW_TABLE_TYPE_NIC_TX) { |
| MLX5_SET64(flow_table_context, ft_mdev, |
| sw_owner_icm_root_0, icm_addr_tx); |
| } else if (table_type == MLX5_FLOW_TABLE_TYPE_FDB) { |
| MLX5_SET64(flow_table_context, ft_mdev, |
| sw_owner_icm_root_0, icm_addr_rx); |
| MLX5_SET64(flow_table_context, ft_mdev, |
| sw_owner_icm_root_1, icm_addr_tx); |
| } |
| } |
| |
| err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
| if (err) |
| return err; |
| |
| *table_id = MLX5_GET(create_flow_table_out, out, table_id); |
| if (!sw_owner && table_type == MLX5_FLOW_TABLE_TYPE_FDB) |
| *fdb_rx_icm_addr = |
| (u64)MLX5_GET(create_flow_table_out, out, icm_address_31_0) | |
| (u64)MLX5_GET(create_flow_table_out, out, icm_address_39_32) << 32 | |
| (u64)MLX5_GET(create_flow_table_out, out, icm_address_63_40) << 40; |
| |
| return 0; |
| } |
| |
| int mlx5dr_cmd_destroy_flow_table(struct mlx5_core_dev *mdev, |
| u32 table_id, |
| u32 table_type) |
| { |
| u32 out[MLX5_ST_SZ_DW(destroy_flow_table_out)] = {}; |
| u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {}; |
| |
| MLX5_SET(destroy_flow_table_in, in, opcode, |
| MLX5_CMD_OP_DESTROY_FLOW_TABLE); |
| MLX5_SET(destroy_flow_table_in, in, table_type, table_type); |
| MLX5_SET(destroy_flow_table_in, in, table_id, table_id); |
| |
| return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
| } |
| |
| int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev, |
| enum mlx5_reformat_ctx_type rt, |
| size_t reformat_size, |
| void *reformat_data, |
| u32 *reformat_id) |
| { |
| u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)] = {}; |
| size_t inlen, cmd_data_sz, cmd_total_sz; |
| void *prctx; |
| void *pdata; |
| void *in; |
| int err; |
| |
| cmd_total_sz = MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in); |
| cmd_data_sz = MLX5_FLD_SZ_BYTES(alloc_packet_reformat_context_in, |
| packet_reformat_context.reformat_data); |
| inlen = ALIGN(cmd_total_sz + reformat_size - cmd_data_sz, 4); |
| in = kvzalloc(inlen, GFP_KERNEL); |
| if (!in) |
| return -ENOMEM; |
| |
| MLX5_SET(alloc_packet_reformat_context_in, in, opcode, |
| MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT); |
| |
| prctx = MLX5_ADDR_OF(alloc_packet_reformat_context_in, in, packet_reformat_context); |
| pdata = MLX5_ADDR_OF(packet_reformat_context_in, prctx, reformat_data); |
| |
| MLX5_SET(packet_reformat_context_in, prctx, reformat_type, rt); |
| MLX5_SET(packet_reformat_context_in, prctx, reformat_data_size, reformat_size); |
| memcpy(pdata, reformat_data, reformat_size); |
| |
| err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); |
| if (err) |
| return err; |
| |
| *reformat_id = MLX5_GET(alloc_packet_reformat_context_out, out, packet_reformat_id); |
| kvfree(in); |
| |
| return err; |
| } |
| |
| void mlx5dr_cmd_destroy_reformat_ctx(struct mlx5_core_dev *mdev, |
| u32 reformat_id) |
| { |
| u32 out[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_out)] = {}; |
| u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)] = {}; |
| |
| MLX5_SET(dealloc_packet_reformat_context_in, in, opcode, |
| MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT); |
| MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id, |
| reformat_id); |
| |
| mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
| } |
| |
| int mlx5dr_cmd_query_gid(struct mlx5_core_dev *mdev, u8 vhca_port_num, |
| u16 index, struct mlx5dr_cmd_gid_attr *attr) |
| { |
| u32 out[MLX5_ST_SZ_DW(query_roce_address_out)] = {}; |
| u32 in[MLX5_ST_SZ_DW(query_roce_address_in)] = {}; |
| int err; |
| |
| MLX5_SET(query_roce_address_in, in, opcode, |
| MLX5_CMD_OP_QUERY_ROCE_ADDRESS); |
| |
| MLX5_SET(query_roce_address_in, in, roce_address_index, index); |
| MLX5_SET(query_roce_address_in, in, vhca_port_num, vhca_port_num); |
| |
| err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
| if (err) |
| return err; |
| |
| memcpy(&attr->gid, |
| MLX5_ADDR_OF(query_roce_address_out, |
| out, roce_address.source_l3_address), |
| sizeof(attr->gid)); |
| memcpy(attr->mac, |
| MLX5_ADDR_OF(query_roce_address_out, out, |
| roce_address.source_mac_47_32), |
| sizeof(attr->mac)); |
| |
| if (MLX5_GET(query_roce_address_out, out, |
| roce_address.roce_version) == MLX5_ROCE_VERSION_2) |
| attr->roce_ver = MLX5_ROCE_VERSION_2; |
| else |
| attr->roce_ver = MLX5_ROCE_VERSION_1; |
| |
| return 0; |
| } |