OSDN Git Service

net/mlx5: E-Switch, Implement devlink port function cmds to control RoCE
authorYishai Hadas <yishaih@nvidia.com>
Tue, 6 Dec 2022 18:51:17 +0000 (20:51 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 8 Dec 2022 04:09:18 +0000 (20:09 -0800)
Implement devlink port function commands to enable / disable RoCE.
This is used to control the RoCE device capabilities.

This patch implement infrastructure which will be used by downstream
patches that will add additional capabilities.

Signed-off-by: Yishai Hadas <yishaih@nvidia.com>
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Acked-by: Saeed Mahameed <saeedm@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Documentation/networking/device_drivers/ethernet/mellanox/mlx5.rst
drivers/net/ethernet/mellanox/mlx5/core/devlink.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
drivers/net/ethernet/mellanox/mlx5/core/vport.c

index 07cfc1b..8b8f95d 100644 (file)
@@ -354,6 +354,16 @@ MAC address setup
 mlx5 driver support devlink port function attr mechanism to setup MAC
 address. (refer to Documentation/networking/devlink/devlink-port.rst)
 
+RoCE capability setup
+---------------------
+Not all mlx5 PCI devices/SFs require RoCE capability.
+
+When RoCE capability is disabled, it saves 1 Mbytes worth of system memory per
+PCI devices/SF.
+
+mlx5 driver support devlink port function attr mechanism to setup RoCE
+capability. (refer to Documentation/networking/devlink/devlink-port.rst)
+
 SF state setup
 --------------
 To use the SF, the user must activate the SF using the SF function state
index 751bc4a..336c7b7 100644 (file)
@@ -314,6 +314,8 @@ static const struct devlink_ops mlx5_devlink_ops = {
        .rate_node_new = mlx5_esw_devlink_rate_node_new,
        .rate_node_del = mlx5_esw_devlink_rate_node_del,
        .rate_leaf_parent_set = mlx5_esw_devlink_rate_parent_set,
+       .port_fn_roce_get = mlx5_devlink_port_fn_roce_get,
+       .port_fn_roce_set = mlx5_devlink_port_fn_roce_set,
 #endif
 #ifdef CONFIG_MLX5_SF_MANAGER
        .port_new = mlx5_devlink_sf_port_new,
index 374e3fb..001fb1e 100644 (file)
@@ -772,6 +772,33 @@ static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw,
                esw_vport_destroy_offloads_acl_tables(esw, vport);
 }
 
+static int mlx5_esw_vport_caps_get(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+{
+       int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+       void *query_ctx;
+       void *hca_caps;
+       int err;
+
+       if (!MLX5_CAP_GEN(esw->dev, vhca_resource_manager))
+               return 0;
+
+       query_ctx = kzalloc(query_out_sz, GFP_KERNEL);
+       if (!query_ctx)
+               return -ENOMEM;
+
+       err = mlx5_vport_get_other_func_cap(esw->dev, vport->vport, query_ctx,
+                                           MLX5_CAP_GENERAL);
+       if (err)
+               goto out_free;
+
+       hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
+       vport->info.roce_enabled = MLX5_GET(cmd_hca_cap, hca_caps, roce);
+
+out_free:
+       kfree(query_ctx);
+       return err;
+}
+
 static int esw_vport_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
 {
        u16 vport_num = vport->vport;
@@ -785,6 +812,10 @@ static int esw_vport_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
        if (mlx5_esw_is_manager_vport(esw, vport_num))
                return 0;
 
+       err = mlx5_esw_vport_caps_get(esw, vport);
+       if (err)
+               goto err_caps;
+
        mlx5_modify_vport_admin_state(esw->dev,
                                      MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
                                      vport_num, 1,
@@ -804,6 +835,10 @@ static int esw_vport_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
                               vport->info.qos, flags);
 
        return 0;
+
+err_caps:
+       esw_vport_cleanup_acl(esw, vport);
+       return err;
 }
 
 /* Don't cleanup vport->info, it's needed to restore vport configuration */
index 42d9df4..eea0521 100644 (file)
@@ -153,6 +153,7 @@ struct mlx5_vport_info {
        u8                      qos;
        u8                      spoofchk: 1;
        u8                      trusted: 1;
+       u8                      roce_enabled: 1;
 };
 
 /* Vport context events */
@@ -508,7 +509,10 @@ int mlx5_devlink_port_function_hw_addr_get(struct devlink_port *port,
 int mlx5_devlink_port_function_hw_addr_set(struct devlink_port *port,
                                           const u8 *hw_addr, int hw_addr_len,
                                           struct netlink_ext_ack *extack);
-
+int mlx5_devlink_port_fn_roce_get(struct devlink_port *port, bool *is_enabled,
+                                 struct netlink_ext_ack *extack);
+int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable,
+                                 struct netlink_ext_ack *extack);
 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type);
 
 int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
index 33dffcb..7618c51 100644 (file)
@@ -4022,3 +4022,111 @@ int mlx5_devlink_port_function_hw_addr_set(struct devlink_port *port,
 
        return mlx5_eswitch_set_vport_mac(esw, vport_num, hw_addr);
 }
+
+static struct mlx5_vport *
+mlx5_devlink_port_fn_get_vport(struct devlink_port *port, struct mlx5_eswitch *esw)
+{
+       u16 vport_num;
+
+       if (!MLX5_CAP_GEN(esw->dev, vhca_resource_manager))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       vport_num = mlx5_esw_devlink_port_index_to_vport_num(port->index);
+       if (!is_port_function_supported(esw, vport_num))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       return mlx5_eswitch_get_vport(esw, vport_num);
+}
+
+int mlx5_devlink_port_fn_roce_get(struct devlink_port *port, bool *is_enabled,
+                                 struct netlink_ext_ack *extack)
+{
+       struct mlx5_eswitch *esw;
+       struct mlx5_vport *vport;
+       int err = -EOPNOTSUPP;
+
+       esw = mlx5_devlink_eswitch_get(port->devlink);
+       if (IS_ERR(esw))
+               return PTR_ERR(esw);
+
+       vport = mlx5_devlink_port_fn_get_vport(port, esw);
+       if (IS_ERR(vport)) {
+               NL_SET_ERR_MSG_MOD(extack, "Invalid port");
+               return PTR_ERR(vport);
+       }
+
+       mutex_lock(&esw->state_lock);
+       if (vport->enabled) {
+               *is_enabled = vport->info.roce_enabled;
+               err = 0;
+       }
+       mutex_unlock(&esw->state_lock);
+       return err;
+}
+
+int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable,
+                                 struct netlink_ext_ack *extack)
+{
+       int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+       struct mlx5_eswitch *esw;
+       struct mlx5_vport *vport;
+       int err = -EOPNOTSUPP;
+       void *query_ctx;
+       void *hca_caps;
+       u16 vport_num;
+
+       esw = mlx5_devlink_eswitch_get(port->devlink);
+       if (IS_ERR(esw))
+               return PTR_ERR(esw);
+
+       vport = mlx5_devlink_port_fn_get_vport(port, esw);
+       if (IS_ERR(vport)) {
+               NL_SET_ERR_MSG_MOD(extack, "Invalid port");
+               return PTR_ERR(vport);
+       }
+       vport_num = vport->vport;
+
+       mutex_lock(&esw->state_lock);
+       if (!vport->enabled) {
+               NL_SET_ERR_MSG_MOD(extack, "Eswitch vport is disabled");
+               goto out;
+       }
+
+       if (vport->info.roce_enabled == enable) {
+               err = 0;
+               goto out;
+       }
+
+       query_ctx = kzalloc(query_out_sz, GFP_KERNEL);
+       if (!query_ctx) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = mlx5_vport_get_other_func_cap(esw->dev, vport_num, query_ctx,
+                                           MLX5_CAP_GENERAL);
+       if (err) {
+               NL_SET_ERR_MSG_MOD(extack, "Failed getting HCA caps");
+               goto out_free;
+       }
+
+       hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
+       memcpy(hca_caps, MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability),
+              MLX5_UN_SZ_BYTES(hca_cap_union));
+       MLX5_SET(cmd_hca_cap, hca_caps, roce, enable);
+
+       err = mlx5_vport_set_other_func_cap(esw->dev, hca_caps, vport_num,
+                                           MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE);
+       if (err) {
+               NL_SET_ERR_MSG_MOD(extack, "Failed setting HCA roce cap");
+               goto out_free;
+       }
+
+       vport->info.roce_enabled = enable;
+
+out_free:
+       kfree(query_ctx);
+out:
+       mutex_unlock(&esw->state_lock);
+       return err;
+}
index 0947398..029305a 100644 (file)
@@ -324,6 +324,8 @@ void mlx5_unload_one_devl_locked(struct mlx5_core_dev *dev);
 int mlx5_load_one(struct mlx5_core_dev *dev, bool recovery);
 int mlx5_load_one_devl_locked(struct mlx5_core_dev *dev, bool recovery);
 
+int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap, u16 function_id,
+                                 u16 opmod);
 #define mlx5_vport_get_other_func_general_cap(dev, fid, out)           \
        mlx5_vport_get_other_func_cap(dev, fid, out, MLX5_CAP_GENERAL)
 
index 7eca758..ba7e3df 100644 (file)
@@ -1173,3 +1173,27 @@ int mlx5_vport_get_other_func_cap(struct mlx5_core_dev *dev, u16 function_id, vo
        return mlx5_cmd_exec_inout(dev, query_hca_cap, in, out);
 }
 EXPORT_SYMBOL_GPL(mlx5_vport_get_other_func_cap);
+
+int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap,
+                                 u16 function_id, u16 opmod)
+{
+       int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
+       void *set_hca_cap;
+       void *set_ctx;
+       int ret;
+
+       set_ctx = kzalloc(set_sz, GFP_KERNEL);
+       if (!set_ctx)
+               return -ENOMEM;
+
+       MLX5_SET(set_hca_cap_in, set_ctx, opcode, MLX5_CMD_OP_SET_HCA_CAP);
+       MLX5_SET(set_hca_cap_in, set_ctx, op_mod, opmod << 1);
+       set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability);
+       memcpy(set_hca_cap, hca_cap, MLX5_ST_SZ_BYTES(cmd_hca_cap));
+       MLX5_SET(set_hca_cap_in, set_ctx, function_id, function_id);
+       MLX5_SET(set_hca_cap_in, set_ctx, other_function, true);
+       ret = mlx5_cmd_exec_in(dev, set_hca_cap, set_ctx);
+
+       kfree(set_ctx);
+       return ret;
+}