// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB /* * Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. */ #include #include #include #include #include #include #include "mlx5_ib.h" #define UVERBS_MODULE_NAME mlx5_ib #include static int UVERBS_HANDLER(MLX5_IB_METHOD_PD_QUERY)( struct uverbs_attr_bundle *attrs) { struct ib_pd *pd = uverbs_attr_get_obj(attrs, MLX5_IB_ATTR_QUERY_PD_HANDLE); struct mlx5_ib_pd *mpd = to_mpd(pd); return uverbs_copy_to(attrs, MLX5_IB_ATTR_QUERY_PD_RESP_PDN, &mpd->pdn, sizeof(mpd->pdn)); } static int fill_vport_icm_addr(struct mlx5_core_dev *mdev, u16 vport, struct mlx5_ib_uapi_query_port *info) { u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {}; u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {}; bool sw_owner_supp; u64 icm_rx; u64 icm_tx; int err; sw_owner_supp = MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, sw_owner) || MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, sw_owner_v2); if (vport == MLX5_VPORT_UPLINK) { icm_rx = MLX5_CAP64_ESW_FLOWTABLE(mdev, sw_steering_uplink_icm_address_rx); icm_tx = MLX5_CAP64_ESW_FLOWTABLE(mdev, sw_steering_uplink_icm_address_tx); } else { MLX5_SET(query_esw_vport_context_in, in, opcode, MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT); MLX5_SET(query_esw_vport_context_in, in, vport_number, vport); MLX5_SET(query_esw_vport_context_in, in, other_vport, true); err = mlx5_cmd_exec_inout(mdev, query_esw_vport_context, in, out); if (err) return err; icm_rx = MLX5_GET64( query_esw_vport_context_out, out, esw_vport_context.sw_steering_vport_icm_address_rx); icm_tx = MLX5_GET64( query_esw_vport_context_out, out, esw_vport_context.sw_steering_vport_icm_address_tx); } if (sw_owner_supp && icm_rx) { info->vport_steering_icm_rx = icm_rx; info->flags |= MLX5_IB_UAPI_QUERY_PORT_VPORT_STEERING_ICM_RX; } if (sw_owner_supp && icm_tx) { info->vport_steering_icm_tx = icm_tx; info->flags |= MLX5_IB_UAPI_QUERY_PORT_VPORT_STEERING_ICM_TX; } return 0; } static int fill_vport_vhca_id(struct mlx5_core_dev *mdev, u16 vport, struct mlx5_ib_uapi_query_port *info) { size_t out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out); u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; void *out; int err; out = kzalloc(out_sz, 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, true); MLX5_SET(query_hca_cap_in, in, function_id, vport); MLX5_SET(query_hca_cap_in, in, op_mod, MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE | HCA_CAP_OPMOD_GET_CUR); err = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_sz); if (err) goto out; info->vport_vhca_id = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id); info->flags |= MLX5_IB_UAPI_QUERY_PORT_VPORT_VHCA_ID; out: kfree(out); return err; } static int fill_switchdev_info(struct mlx5_ib_dev *dev, u32 port_num, struct mlx5_ib_uapi_query_port *info) { struct mlx5_eswitch_rep *rep; struct mlx5_core_dev *mdev; int err; rep = dev->port[port_num - 1].rep; if (!rep) return -EOPNOTSUPP; mdev = mlx5_eswitch_get_core_dev(rep->esw); if (!mdev) return -EINVAL; info->vport = rep->vport; info->flags |= MLX5_IB_UAPI_QUERY_PORT_VPORT; if (rep->vport != MLX5_VPORT_UPLINK) { err = fill_vport_vhca_id(mdev, rep->vport, info); if (err) return err; } info->esw_owner_vhca_id = MLX5_CAP_GEN(mdev, vhca_id); info->flags |= MLX5_IB_UAPI_QUERY_PORT_ESW_OWNER_VHCA_ID; err = fill_vport_icm_addr(mdev, rep->vport, info); if (err) return err; if (mlx5_eswitch_vport_match_metadata_enabled(rep->esw)) { info->reg_c0.value = mlx5_eswitch_get_vport_metadata_for_match( rep->esw, rep->vport); info->reg_c0.mask = mlx5_eswitch_get_vport_metadata_mask(); info->flags |= MLX5_IB_UAPI_QUERY_PORT_VPORT_REG_C0; } return 0; } static int UVERBS_HANDLER(MLX5_IB_METHOD_QUERY_PORT)( struct uverbs_attr_bundle *attrs) { struct mlx5_ib_uapi_query_port info = {}; struct mlx5_ib_ucontext *c; struct mlx5_ib_dev *dev; u32 port_num; int ret; if (uverbs_copy_from(&port_num, attrs, MLX5_IB_ATTR_QUERY_PORT_PORT_NUM)) return -EFAULT; c = to_mucontext(ib_uverbs_get_ucontext(attrs)); if (IS_ERR(c)) return PTR_ERR(c); dev = to_mdev(c->ibucontext.device); if (!rdma_is_port_valid(&dev->ib_dev, port_num)) return -EINVAL; if (mlx5_eswitch_mode(dev->mdev) == MLX5_ESWITCH_OFFLOADS) { ret = fill_switchdev_info(dev, port_num, &info); if (ret) return ret; } return uverbs_copy_to_struct_or_zero(attrs, MLX5_IB_ATTR_QUERY_PORT, &info, sizeof(info)); } DECLARE_UVERBS_NAMED_METHOD( MLX5_IB_METHOD_QUERY_PORT, UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_QUERY_PORT_PORT_NUM, UVERBS_ATTR_TYPE(u32), UA_MANDATORY), UVERBS_ATTR_PTR_OUT( MLX5_IB_ATTR_QUERY_PORT, UVERBS_ATTR_STRUCT(struct mlx5_ib_uapi_query_port, reg_c0), UA_MANDATORY)); ADD_UVERBS_METHODS(mlx5_ib_device, UVERBS_OBJECT_DEVICE, &UVERBS_METHOD(MLX5_IB_METHOD_QUERY_PORT)); DECLARE_UVERBS_NAMED_METHOD( MLX5_IB_METHOD_PD_QUERY, UVERBS_ATTR_IDR(MLX5_IB_ATTR_QUERY_PD_HANDLE, UVERBS_OBJECT_PD, UVERBS_ACCESS_READ, UA_MANDATORY), UVERBS_ATTR_PTR_OUT(MLX5_IB_ATTR_QUERY_PD_RESP_PDN, UVERBS_ATTR_TYPE(u32), UA_MANDATORY)); ADD_UVERBS_METHODS(mlx5_ib_pd, UVERBS_OBJECT_PD, &UVERBS_METHOD(MLX5_IB_METHOD_PD_QUERY)); const struct uapi_definition mlx5_ib_std_types_defs[] = { UAPI_DEF_CHAIN_OBJ_TREE( UVERBS_OBJECT_PD, &mlx5_ib_pd), UAPI_DEF_CHAIN_OBJ_TREE( UVERBS_OBJECT_DEVICE, &mlx5_ib_device), {}, };