// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB /* Copyright (c) 2019 Mellanox Technologies */ #include #include #include #include "lib/mlx5.h" #include "eswitch.h" #include "fs_core.h" #include "rdma.h" static void mlx5_rdma_disable_roce_steering(struct mlx5_core_dev *dev) { struct mlx5_core_roce *roce = &dev->priv.roce; mlx5_del_flow_rules(roce->allow_rule); mlx5_destroy_flow_group(roce->fg); mlx5_destroy_flow_table(roce->ft); } static int mlx5_rdma_enable_roce_steering(struct mlx5_core_dev *dev) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_core_roce *roce = &dev->priv.roce; struct mlx5_flow_handle *flow_rule = NULL; struct mlx5_flow_table_attr ft_attr = {}; struct mlx5_flow_namespace *ns = NULL; struct mlx5_flow_act flow_act = {}; struct mlx5_flow_spec *spec; struct mlx5_flow_table *ft; struct mlx5_flow_group *fg; void *match_criteria; u32 *flow_group_in; void *misc; int err; if (!(MLX5_CAP_FLOWTABLE_RDMA_RX(dev, ft_support) && MLX5_CAP_FLOWTABLE_RDMA_RX(dev, table_miss_action_domain))) return -EOPNOTSUPP; flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { kvfree(flow_group_in); return -ENOMEM; } ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_RDMA_RX_KERNEL); if (!ns) { mlx5_core_err(dev, "Failed to get RDMA RX namespace"); err = -EOPNOTSUPP; goto free; } ft_attr.max_fte = 1; ft = mlx5_create_flow_table(ns, &ft_attr); if (IS_ERR(ft)) { mlx5_core_err(dev, "Failed to create RDMA RX flow table"); err = PTR_ERR(ft); goto free; } MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_MISC_PARAMETERS); match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria); MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port); fg = mlx5_create_flow_group(ft, flow_group_in); if (IS_ERR(fg)) { err = PTR_ERR(fg); mlx5_core_err(dev, "Failed to create RDMA RX flow group err(%d)\n", err); goto destroy_flow_table; } spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS; misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); MLX5_SET(fte_match_set_misc, misc, source_port, dev->priv.eswitch->manager_vport); misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters); MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port); flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW; flow_rule = mlx5_add_flow_rules(ft, spec, &flow_act, NULL, 0); if (IS_ERR(flow_rule)) { err = PTR_ERR(flow_rule); mlx5_core_err(dev, "Failed to add RoCE allow rule, err=%d\n", err); goto destroy_flow_group; } kvfree(spec); kvfree(flow_group_in); roce->ft = ft; roce->fg = fg; roce->allow_rule = flow_rule; return 0; destroy_flow_group: mlx5_destroy_flow_group(fg); destroy_flow_table: mlx5_destroy_flow_table(ft); free: kvfree(spec); kvfree(flow_group_in); return err; } static void mlx5_rdma_del_roce_addr(struct mlx5_core_dev *dev) { mlx5_core_roce_gid_set(dev, 0, 0, 0, NULL, NULL, false, 0, 0); } static void mlx5_rdma_make_default_gid(struct mlx5_core_dev *dev, union ib_gid *gid) { u8 hw_id[ETH_ALEN]; mlx5_query_mac_address(dev, hw_id); gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); addrconf_addr_eui48(&gid->raw[8], hw_id); } static int mlx5_rdma_add_roce_addr(struct mlx5_core_dev *dev) { union ib_gid gid; u8 mac[ETH_ALEN]; mlx5_rdma_make_default_gid(dev, &gid); return mlx5_core_roce_gid_set(dev, 0, MLX5_ROCE_VERSION_1, 0, gid.raw, mac, false, 0, 1); } void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev) { struct mlx5_core_roce *roce = &dev->priv.roce; if (!roce->ft) return; mlx5_rdma_disable_roce_steering(dev); mlx5_rdma_del_roce_addr(dev); mlx5_nic_vport_disable_roce(dev); } void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev) { int err; err = mlx5_nic_vport_enable_roce(dev); if (err) { mlx5_core_err(dev, "Failed to enable RoCE: %d\n", err); return; } err = mlx5_rdma_add_roce_addr(dev); if (err) { mlx5_core_err(dev, "Failed to add RoCE address: %d\n", err); goto disable_roce; } err = mlx5_rdma_enable_roce_steering(dev); if (err) { mlx5_core_err(dev, "Failed to enable RoCE steering: %d\n", err); goto del_roce_addr; } return; del_roce_addr: mlx5_rdma_del_roce_addr(dev); disable_roce: mlx5_nic_vport_disable_roce(dev); return; }