@@ -192,6 +192,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_function_state_get = mlx5_devlink_sf_port_fn_state_get,
+ .port_function_state_set = mlx5_devlink_sf_port_fn_state_set,
#endif
.flash_update = mlx5_devlink_flash_update,
.info_get = mlx5_devlink_info_get,
@@ -4,6 +4,7 @@
#include <linux/mlx5/driver.h>
#include "eswitch.h"
#include "priv.h"
+#include "sf/dev/dev.h"
struct mlx5_sf {
struct devlink_port dl_port;
@@ -11,6 +12,7 @@ struct mlx5_sf {
u32 usr_sfnum;
u16 sw_id;
u16 hw_fn_id;
+ enum devlink_port_function_state state;
};
struct mlx5_sf_table {
@@ -115,6 +117,7 @@ mlx5_sf_alloc(struct mlx5_sf_table *table, u32 sfnum, struct netlink_ext_ack *ex
if (err)
goto id_err;
+ sf->state = DEVLINK_PORT_FUNCTION_STATE_INACTIVE;
dl_port_index = mlx5_esw_vport_to_devlink_port_index(table->dev, sf->hw_fn_id);
sf->port_index = dl_port_index;
sf->usr_sfnum = sfnum;
@@ -156,6 +159,126 @@ static void mlx5_sf_table_put(struct mlx5_sf_table *table)
complete(&table->disable_complete);
}
+static int
+mlx5_sf_state_get(struct mlx5_core_dev *dev, struct mlx5_sf *sf,
+ enum devlink_port_function_state *state,
+ enum devlink_port_function_opstate *opstate)
+{
+ int err = 0;
+
+ *state = sf->state;
+ switch (sf->state) {
+ case DEVLINK_PORT_FUNCTION_STATE_ACTIVE:
+ *opstate = DEVLINK_PORT_FUNCTION_OPSTATE_ATTACHED;
+ break;
+ case DEVLINK_PORT_FUNCTION_STATE_INACTIVE:
+ *opstate = DEVLINK_PORT_FUNCTION_OPSTATE_DETACHED;
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+int mlx5_devlink_sf_port_fn_state_get(struct devlink *devlink, struct devlink_port *dl_port,
+ enum devlink_port_function_state *state,
+ enum devlink_port_function_opstate *opstate,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_core_dev *dev = devlink_priv(devlink);
+ struct mlx5_sf_table *table;
+ int err = -EOPNOTSUPP;
+ struct mlx5_sf *sf;
+
+ table = mlx5_sf_table_try_get(dev);
+ if (!table)
+ return -EOPNOTSUPP;
+
+ sf = mlx5_sf_lookup_by_index(table, dl_port->index);
+ if (!sf)
+ goto sf_err;
+ err = mlx5_sf_state_get(dev, sf, state, opstate);
+sf_err:
+ mlx5_sf_table_put(table);
+ return err;
+}
+
+static int mlx5_sf_activate(struct mlx5_core_dev *dev, struct mlx5_sf *sf)
+{
+ int err;
+
+ err = mlx5_cmd_sf_enable_hca(dev, sf->hw_fn_id);
+ if (err)
+ return err;
+
+ err = mlx5_sf_dev_add(dev, sf->sw_id, sf->usr_sfnum);
+ if (err)
+ goto dev_err;
+
+ sf->state = DEVLINK_PORT_FUNCTION_STATE_ACTIVE;
+ return 0;
+
+dev_err:
+ mlx5_cmd_sf_disable_hca(dev, sf->hw_fn_id);
+ return err;
+}
+
+static int mlx5_sf_deactivate(struct mlx5_core_dev *dev, struct mlx5_sf *sf)
+{
+ int err;
+
+ mlx5_sf_dev_del(dev, sf->sw_id);
+ err = mlx5_cmd_sf_disable_hca(dev, sf->hw_fn_id);
+ if (err)
+ return err;
+ sf->state = DEVLINK_PORT_FUNCTION_STATE_INACTIVE;
+ return 0;
+}
+
+static int mlx5_sf_state_set(struct mlx5_core_dev *dev, struct mlx5_sf *sf,
+ enum devlink_port_function_state state)
+{
+ int err;
+
+ if (sf->state == state)
+ return 0;
+ if (state == DEVLINK_PORT_FUNCTION_STATE_ACTIVE)
+ err = mlx5_sf_activate(dev, sf);
+ else if (state == DEVLINK_PORT_FUNCTION_STATE_INACTIVE)
+ err = mlx5_sf_deactivate(dev, sf);
+ else
+ err = -EINVAL;
+ return err;
+}
+
+int mlx5_devlink_sf_port_fn_state_set(struct devlink *devlink, struct devlink_port *dl_port,
+ enum devlink_port_function_state state,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_core_dev *dev = devlink_priv(devlink);
+ struct mlx5_sf_table *table;
+ struct mlx5_sf *sf;
+ int err;
+
+ table = mlx5_sf_table_try_get(dev);
+ if (!table) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Port state set is only supported in eswitch switchdev mode or SF ports are disabled.");
+ return -EOPNOTSUPP;
+ }
+ sf = mlx5_sf_lookup_by_index(table, dl_port->index);
+ if (!sf) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ err = mlx5_sf_state_set(dev, sf, state);
+out:
+ mlx5_sf_table_put(table);
+ return err;
+}
+
static int mlx5_sf_add(struct mlx5_core_dev *dev, struct mlx5_sf_table *table,
const struct devlink_port_new_attrs *new_attr,
struct netlink_ext_ack *extack)
@@ -184,6 +307,10 @@ static void mlx5_sf_del(struct mlx5_core_dev *dev, struct mlx5_sf_table *table,
{
struct mlx5_eswitch *esw = dev->priv.eswitch;
+ if (sf->state == DEVLINK_PORT_FUNCTION_STATE_ACTIVE) {
+ mlx5_sf_dev_del(dev, sf->sw_id);
+ mlx5_cmd_sf_disable_hca(dev, sf->hw_fn_id);
+ }
mlx5_esw_offloads_sf_vport_disable(esw, sf->hw_fn_id);
mlx5_sf_free(table, sf);
}
@@ -343,6 +470,7 @@ int mlx5_sf_table_init(struct mlx5_core_dev *dev)
table->dev = dev;
ida_init(&table->fn_ida);
+ refcount_set(&table->refcount, 0);
dev->priv.sf_table = table;
table->esw_nb.notifier_call = mlx5_sf_esw_event;
err = mlx5_esw_event_notifier_register(dev->priv.eswitch, &table->esw_nb);
@@ -25,6 +25,13 @@ int mlx5_devlink_sf_port_new(struct devlink *devlink, const struct devlink_port_
struct netlink_ext_ack *extack);
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_function_state *state,
+ enum devlink_port_function_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_function_state state,
+ struct netlink_ext_ack *extack);
#else