#include "fs_core.h"
#include "eswitch.h"
int mlx5_esw_adj_vport_modify(struct mlx5_core_dev *dev, u16 vport,
bool connect)
{
u32 in[MLX5_ST_SZ_DW(modify_vport_state_in)] = {};
MLX5_SET(modify_vport_state_in, in, opcode,
MLX5_CMD_OP_MODIFY_VPORT_STATE);
MLX5_SET(modify_vport_state_in, in, op_mod,
MLX5_VPORT_STATE_OP_MOD_ESW_VPORT);
MLX5_SET(modify_vport_state_in, in, other_vport, 1);
MLX5_SET(modify_vport_state_in, in, vport_number, vport);
MLX5_SET(modify_vport_state_in, in, ingress_connect_valid, 1);
MLX5_SET(modify_vport_state_in, in, egress_connect_valid, 1);
MLX5_SET(modify_vport_state_in, in, ingress_connect, connect);
MLX5_SET(modify_vport_state_in, in, egress_connect, connect);
MLX5_SET(modify_vport_state_in, in, admin_state, connect);
return mlx5_cmd_exec_in(dev, modify_vport_state, in);
}
static void mlx5_esw_destroy_esw_vport(struct mlx5_core_dev *dev, u16 vport)
{
u32 in[MLX5_ST_SZ_DW(destroy_esw_vport_in)] = {};
MLX5_SET(destroy_esw_vport_in, in, opcode,
MLX5_CMD_OPCODE_DESTROY_ESW_VPORT);
MLX5_SET(destroy_esw_vport_in, in, vport_num, vport);
mlx5_cmd_exec_in(dev, destroy_esw_vport, in);
}
static int mlx5_esw_create_esw_vport(struct mlx5_core_dev *dev, u16 vhca_id,
u16 *vport_num)
{
u32 out[MLX5_ST_SZ_DW(create_esw_vport_out)] = {};
u32 in[MLX5_ST_SZ_DW(create_esw_vport_in)] = {};
int err;
MLX5_SET(create_esw_vport_in, in, opcode,
MLX5_CMD_OPCODE_CREATE_ESW_VPORT);
MLX5_SET(create_esw_vport_in, in, managed_vhca_id, vhca_id);
err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
if (!err)
*vport_num = MLX5_GET(create_esw_vport_out, out, vport_num);
return err;
}
static int mlx5_esw_adj_vport_create(struct mlx5_eswitch *esw, u16 vhca_id,
const void *rid_info_reg)
{
struct mlx5_vport *vport;
u16 vport_num;
int err;
err = mlx5_esw_create_esw_vport(esw->dev, vhca_id, &vport_num);
if (err) {
esw_warn(esw->dev,
"Failed to create adjacent vport for vhca_id %d, err %d\n",
vhca_id, err);
return err;
}
esw_debug(esw->dev, "Created adjacent vport[%d] %d for vhca_id 0x%x\n",
esw->last_vport_idx, vport_num, vhca_id);
err = mlx5_esw_vport_alloc(esw, esw->last_vport_idx++, vport_num);
if (err)
goto destroy_esw_vport;
xa_set_mark(&esw->vports, vport_num, MLX5_ESW_VPT_VF);
vport = mlx5_eswitch_get_vport(esw, vport_num);
vport->adjacent = true;
vport->vhca_id = vhca_id;
vport->adj_info.parent_pci_devfn =
MLX5_GET(function_vhca_rid_info_reg, rid_info_reg,
parent_pci_device_function);
vport->adj_info.function_id =
MLX5_GET(function_vhca_rid_info_reg, rid_info_reg, function_id);
mlx5_fs_vport_egress_acl_ns_add(esw->dev->priv.steering, vport->index);
mlx5_fs_vport_ingress_acl_ns_add(esw->dev->priv.steering, vport->index);
err = mlx5_esw_offloads_rep_add(esw, vport);
if (err)
goto acl_ns_remove;
return 0;
acl_ns_remove:
mlx5_fs_vport_ingress_acl_ns_remove(esw->dev->priv.steering,
vport->index);
mlx5_fs_vport_egress_acl_ns_remove(esw->dev->priv.steering,
vport->index);
mlx5_esw_vport_free(esw, vport);
destroy_esw_vport:
mlx5_esw_destroy_esw_vport(esw->dev, vport_num);
return err;
}
static void mlx5_esw_adj_vport_destroy(struct mlx5_eswitch *esw,
struct mlx5_vport *vport)
{
u16 vport_num = vport->vport;
esw_debug(esw->dev, "Destroying adjacent vport %d for vhca_id 0x%x\n",
vport_num, vport->vhca_id);
mlx5_esw_offloads_rep_remove(esw, vport);
mlx5_fs_vport_egress_acl_ns_remove(esw->dev->priv.steering,
vport->index);
mlx5_fs_vport_ingress_acl_ns_remove(esw->dev->priv.steering,
vport->index);
mlx5_esw_vport_free(esw, vport);
esw->last_vport_idx--;
mlx5_esw_destroy_esw_vport(esw->dev, vport_num);
}
void mlx5_esw_adjacent_vhcas_cleanup(struct mlx5_eswitch *esw)
{
struct mlx5_vport *vport;
unsigned long i;
if (!MLX5_CAP_GEN_2(esw->dev, delegated_vhca_max))
return;
mlx5_esw_for_each_vf_vport(esw, i, vport, U16_MAX) {
if (!vport->adjacent)
continue;
mlx5_esw_adj_vport_destroy(esw, vport);
}
}
void mlx5_esw_adjacent_vhcas_setup(struct mlx5_eswitch *esw)
{
u32 delegated_vhca_max = MLX5_CAP_GEN_2(esw->dev, delegated_vhca_max);
u32 in[MLX5_ST_SZ_DW(query_delegated_vhca_in)] = {};
int outlen, err, i = 0;
u8 *out;
u32 count;
if (!delegated_vhca_max)
return;
outlen = MLX5_ST_SZ_BYTES(query_delegated_vhca_out) +
delegated_vhca_max *
MLX5_ST_SZ_BYTES(delegated_function_vhca_rid_info);
esw_debug(esw->dev, "delegated_vhca_max=%d\n", delegated_vhca_max);
out = kvzalloc(outlen, GFP_KERNEL);
if (!out)
return;
MLX5_SET(query_delegated_vhca_in, in, opcode,
MLX5_CMD_OPCODE_QUERY_DELEGATED_VHCA);
err = mlx5_cmd_exec(esw->dev, in, sizeof(in), out, outlen);
if (err) {
kvfree(out);
esw_warn(esw->dev, "Failed to query delegated vhca, err %d\n",
err);
return;
}
count = MLX5_GET(query_delegated_vhca_out, out, functions_count);
esw_debug(esw->dev, "Delegated vhca functions count %d\n", count);
for (i = 0; i < count; i++) {
const void *rid_info, *rid_info_reg;
u16 vhca_id;
rid_info = MLX5_ADDR_OF(query_delegated_vhca_out, out,
delegated_function_vhca_rid_info[i]);
rid_info_reg = MLX5_ADDR_OF(delegated_function_vhca_rid_info,
rid_info, function_vhca_rid_info);
vhca_id = MLX5_GET(function_vhca_rid_info_reg, rid_info_reg,
vhca_id);
esw_debug(esw->dev, "Delegating vhca_id 0x%x\n", vhca_id);
err = mlx5_esw_adj_vport_create(esw, vhca_id, rid_info_reg);
if (err) {
esw_warn(esw->dev,
"Failed to init adjacent vhca 0x%x, err %d\n",
vhca_id, err);
break;
}
}
kvfree(out);
}