Commit 6a327321 authored by Parav Pandit's avatar Parav Pandit Committed by Saeed Mahameed

net/mlx5: SF, Port function state change support

Support changing the state of the SF port's function through devlink.
When activating the SF port's function, enable the hca in the device
followed by adding its auxiliary device.
When deactivating the SF port's function, delete its auxiliary device
followed by disabling the vHCA.

Port function attributes get/set callbacks are invoked with devlink
instance lock held. Such callbacks need to synchronize with sf port
table getting disabled either via sriov sysfs callback. Such callbacks
synchronize with table disable context holding table refcount.

$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev

$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false

$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:06:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
  function:
    hw_addr 00:00:00:00:00:00 state inactive opstate detached

$ devlink port show ens2f0npf0sf88
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
  function:
    hw_addr 00:00:00:00:88:88 state inactive opstate detached

$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active

$ devlink port show ens2f0npf0sf88 -jp
{
    "port": {
        "pci/0000:06:00.0/32768": {
            "type": "eth",
            "netdev": "ens2f0npf0sf88",
            "flavour": "pcisf",
            "controller": 0,
            "pfnum": 0,
            "sfnum": 88,
            "external": false,
            "splittable": false,
            "function": {
                "hw_addr": "00:00:00:00:88:88",
                "state": "active",
                "opstate": "attached"
            }
        }
    }
}

On port function activation, an auxiliary device is created in below
example.

$ devlink dev show
devlink dev show auxiliary/mlx5_core.sf.4

$ devlink port show auxiliary/mlx5_core.sf.4/1
auxiliary/mlx5_core.sf.4/1: type eth netdev p0sf88 flavour virtual port 0 splittable false
Signed-off-by: default avatarParav Pandit <parav@nvidia.com>
Reviewed-by: default avatarVu Pham <vuhuong@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent 8f010541
......@@ -195,6 +195,8 @@ static const struct devlink_ops mlx5_devlink_ops = {
#ifdef CONFIG_MLX5_SF_MANAGER
.port_new = mlx5_devlink_sf_port_new,
.port_del = mlx5_devlink_sf_port_del,
.port_fn_state_get = mlx5_devlink_sf_port_fn_state_get,
.port_fn_state_set = mlx5_devlink_sf_port_fn_state_set,
#endif
.flash_update = mlx5_devlink_flash_update,
.info_get = mlx5_devlink_info_get,
......
......@@ -75,6 +75,7 @@
#include "diag/rsc_dump.h"
#include "sf/vhca_event.h"
#include "sf/dev/dev.h"
#include "sf/sf.h"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver");
......@@ -1161,6 +1162,12 @@ static int mlx5_load(struct mlx5_core_dev *dev)
mlx5_vhca_event_start(dev);
err = mlx5_sf_hw_table_create(dev);
if (err) {
mlx5_core_err(dev, "sf table create failed %d\n", err);
goto err_vhca;
}
err = mlx5_ec_init(dev);
if (err) {
mlx5_core_err(dev, "Failed to init embedded CPU\n");
......@@ -1180,6 +1187,8 @@ static int mlx5_load(struct mlx5_core_dev *dev)
err_sriov:
mlx5_ec_cleanup(dev);
err_ec:
mlx5_sf_hw_table_destroy(dev);
err_vhca:
mlx5_vhca_event_stop(dev);
mlx5_cleanup_fs(dev);
err_fs:
......@@ -1209,6 +1218,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev)
mlx5_sf_dev_table_destroy(dev);
mlx5_sriov_detach(dev);
mlx5_ec_cleanup(dev);
mlx5_sf_hw_table_destroy(dev);
mlx5_vhca_event_stop(dev);
mlx5_cleanup_fs(dev);
mlx5_accel_ipsec_cleanup(dev);
......
......@@ -25,3 +25,25 @@ int mlx5_cmd_dealloc_sf(struct mlx5_core_dev *dev, u16 function_id)
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
int mlx5_cmd_sf_enable_hca(struct mlx5_core_dev *dev, u16 func_id)
{
u32 out[MLX5_ST_SZ_DW(enable_hca_out)] = {};
u32 in[MLX5_ST_SZ_DW(enable_hca_in)] = {};
MLX5_SET(enable_hca_in, in, opcode, MLX5_CMD_OP_ENABLE_HCA);
MLX5_SET(enable_hca_in, in, function_id, func_id);
MLX5_SET(enable_hca_in, in, embedded_cpu_function, 0);
return mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
}
int mlx5_cmd_sf_disable_hca(struct mlx5_core_dev *dev, u16 func_id)
{
u32 out[MLX5_ST_SZ_DW(disable_hca_out)] = {};
u32 in[MLX5_ST_SZ_DW(disable_hca_in)] = {};
MLX5_SET(disable_hca_in, in, opcode, MLX5_CMD_OP_DISABLE_HCA);
MLX5_SET(disable_hca_in, in, function_id, func_id);
MLX5_SET(enable_hca_in, in, embedded_cpu_function, 0);
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
......@@ -4,11 +4,14 @@
#include "vhca_event.h"
#include "priv.h"
#include "sf.h"
#include "mlx5_ifc_vhca_event.h"
#include "vhca_event.h"
#include "ecpf.h"
struct mlx5_sf_hw {
u32 usr_sfnum;
u8 allocated: 1;
u8 pending_delete: 1;
};
struct mlx5_sf_hw_table {
......@@ -16,6 +19,8 @@ struct mlx5_sf_hw_table {
struct mlx5_sf_hw *sfs;
int max_local_functions;
u8 ecpu: 1;
struct mutex table_lock; /* Serializes sf deletion and vhca state change handler. */
struct notifier_block vhca_nb;
};
u16 mlx5_sf_sw_to_hw_id(const struct mlx5_core_dev *dev, u16 sw_id)
......@@ -23,6 +28,11 @@ u16 mlx5_sf_sw_to_hw_id(const struct mlx5_core_dev *dev, u16 sw_id)
return sw_id + mlx5_sf_start_function_id(dev);
}
static u16 mlx5_sf_hw_to_sw_id(const struct mlx5_core_dev *dev, u16 hw_id)
{
return hw_id - mlx5_sf_start_function_id(dev);
}
int mlx5_sf_hw_table_sf_alloc(struct mlx5_core_dev *dev, u32 usr_sfnum)
{
struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
......@@ -34,10 +44,13 @@ int mlx5_sf_hw_table_sf_alloc(struct mlx5_core_dev *dev, u32 usr_sfnum)
if (!table->max_local_functions)
return -EOPNOTSUPP;
mutex_lock(&table->table_lock);
/* Check if sf with same sfnum already exists or not. */
for (i = 0; i < table->max_local_functions; i++) {
if (table->sfs[i].allocated && table->sfs[i].usr_sfnum == usr_sfnum)
return -EEXIST;
if (table->sfs[i].allocated && table->sfs[i].usr_sfnum == usr_sfnum) {
err = -EEXIST;
goto exist_err;
}
}
/* Find the free entry and allocate the entry from the array */
......@@ -63,16 +76,19 @@ int mlx5_sf_hw_table_sf_alloc(struct mlx5_core_dev *dev, u32 usr_sfnum)
if (err)
goto vhca_err;
mutex_unlock(&table->table_lock);
return sw_id;
vhca_err:
mlx5_cmd_dealloc_sf(table->dev, hw_fn_id);
err:
table->sfs[i].allocated = false;
exist_err:
mutex_unlock(&table->table_lock);
return err;
}
void mlx5_sf_hw_table_sf_free(struct mlx5_core_dev *dev, u16 id)
static void _mlx5_sf_hw_id_free(struct mlx5_core_dev *dev, u16 id)
{
struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
u16 hw_fn_id;
......@@ -80,6 +96,50 @@ void mlx5_sf_hw_table_sf_free(struct mlx5_core_dev *dev, u16 id)
hw_fn_id = mlx5_sf_sw_to_hw_id(table->dev, id);
mlx5_cmd_dealloc_sf(table->dev, hw_fn_id);
table->sfs[id].allocated = false;
table->sfs[id].pending_delete = false;
}
void mlx5_sf_hw_table_sf_free(struct mlx5_core_dev *dev, u16 id)
{
struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
mutex_lock(&table->table_lock);
_mlx5_sf_hw_id_free(dev, id);
mutex_unlock(&table->table_lock);
}
void mlx5_sf_hw_table_sf_deferred_free(struct mlx5_core_dev *dev, u16 id)
{
struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
u32 out[MLX5_ST_SZ_DW(query_vhca_state_out)] = {};
u16 hw_fn_id;
u8 state;
int err;
hw_fn_id = mlx5_sf_sw_to_hw_id(dev, id);
mutex_lock(&table->table_lock);
err = mlx5_cmd_query_vhca_state(dev, hw_fn_id, table->ecpu, out, sizeof(out));
if (err)
goto err;
state = MLX5_GET(query_vhca_state_out, out, vhca_state_context.vhca_state);
if (state == MLX5_VHCA_STATE_ALLOCATED) {
mlx5_cmd_dealloc_sf(table->dev, hw_fn_id);
table->sfs[id].allocated = false;
} else {
table->sfs[id].pending_delete = true;
}
err:
mutex_unlock(&table->table_lock);
}
static void mlx5_sf_hw_dealloc_all(struct mlx5_sf_hw_table *table)
{
int i;
for (i = 0; i < table->max_local_functions; i++) {
if (table->sfs[i].allocated)
_mlx5_sf_hw_id_free(table->dev, i);
}
}
int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev)
......@@ -88,7 +148,7 @@ int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev)
struct mlx5_sf_hw *sfs;
int max_functions;
if (!mlx5_sf_supported(dev))
if (!mlx5_sf_supported(dev) || !mlx5_vhca_event_supported(dev))
return 0;
max_functions = mlx5_sf_max_functions(dev);
......@@ -100,6 +160,7 @@ int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev)
if (!sfs)
goto table_err;
mutex_init(&table->table_lock);
table->dev = dev;
table->sfs = sfs;
table->max_local_functions = max_functions;
......@@ -120,6 +181,53 @@ void mlx5_sf_hw_table_cleanup(struct mlx5_core_dev *dev)
if (!table)
return;
mutex_destroy(&table->table_lock);
kfree(table->sfs);
kfree(table);
}
static int mlx5_sf_hw_vhca_event(struct notifier_block *nb, unsigned long opcode, void *data)
{
struct mlx5_sf_hw_table *table = container_of(nb, struct mlx5_sf_hw_table, vhca_nb);
const struct mlx5_vhca_state_event *event = data;
struct mlx5_sf_hw *sf_hw;
u16 sw_id;
if (event->new_vhca_state != MLX5_VHCA_STATE_ALLOCATED)
return 0;
sw_id = mlx5_sf_hw_to_sw_id(table->dev, event->function_id);
sf_hw = &table->sfs[sw_id];
mutex_lock(&table->table_lock);
/* SF driver notified through firmware that SF is finally detached.
* Hence recycle the sf hardware id for reuse.
*/
if (sf_hw->allocated && sf_hw->pending_delete)
_mlx5_sf_hw_id_free(table->dev, sw_id);
mutex_unlock(&table->table_lock);
return 0;
}
int mlx5_sf_hw_table_create(struct mlx5_core_dev *dev)
{
struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
if (!table)
return 0;
table->vhca_nb.notifier_call = mlx5_sf_hw_vhca_event;
return mlx5_vhca_event_notifier_register(table->dev, &table->vhca_nb);
}
void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev)
{
struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
if (!table)
return;
mlx5_vhca_event_notifier_unregister(table->dev, &table->vhca_nb);
/* Dealloc SFs whose firmware event has been missed. */
mlx5_sf_hw_dealloc_all(table);
}
......@@ -9,9 +9,13 @@
int mlx5_cmd_alloc_sf(struct mlx5_core_dev *dev, u16 function_id);
int mlx5_cmd_dealloc_sf(struct mlx5_core_dev *dev, u16 function_id);
int mlx5_cmd_sf_enable_hca(struct mlx5_core_dev *dev, u16 func_id);
int mlx5_cmd_sf_disable_hca(struct mlx5_core_dev *dev, u16 func_id);
u16 mlx5_sf_sw_to_hw_id(const struct mlx5_core_dev *dev, u16 sw_id);
int mlx5_sf_hw_table_sf_alloc(struct mlx5_core_dev *dev, u32 usr_sfnum);
void mlx5_sf_hw_table_sf_free(struct mlx5_core_dev *dev, u16 id);
void mlx5_sf_hw_table_sf_deferred_free(struct mlx5_core_dev *dev, u16 id);
#endif
......@@ -47,6 +47,9 @@ static inline u16 mlx5_sf_max_functions(const struct mlx5_core_dev *dev)
int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev);
void mlx5_sf_hw_table_cleanup(struct mlx5_core_dev *dev);
int mlx5_sf_hw_table_create(struct mlx5_core_dev *dev);
void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev);
int mlx5_sf_table_init(struct mlx5_core_dev *dev);
void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev);
......@@ -56,7 +59,13 @@ int mlx5_devlink_sf_port_new(struct devlink *devlink,
unsigned int *new_port_index);
int mlx5_devlink_sf_port_del(struct devlink *devlink, unsigned int port_index,
struct netlink_ext_ack *extack);
int mlx5_devlink_sf_port_fn_state_get(struct devlink *devlink, struct devlink_port *dl_port,
enum devlink_port_fn_state *state,
enum devlink_port_fn_opstate *opstate,
struct netlink_ext_ack *extack);
int mlx5_devlink_sf_port_fn_state_set(struct devlink *devlink, struct devlink_port *dl_port,
enum devlink_port_fn_state state,
struct netlink_ext_ack *extack);
#else
static inline int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev)
......@@ -68,6 +77,15 @@ static inline void mlx5_sf_hw_table_cleanup(struct mlx5_core_dev *dev)
{
}
static inline int mlx5_sf_hw_table_create(struct mlx5_core_dev *dev)
{
return 0;
}
static inline void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev)
{
}
static inline int mlx5_sf_table_init(struct mlx5_core_dev *dev)
{
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment