From: Cosmin Ratiu <[email protected]> Qos cleanup is a complex affair, because of the two modes of operation (legacy and switchdev).
Leaf QoS is removed: 1. In legacy mode by esw_vport_cleanup() -> mlx5_esw_qos_vport_disable() 2. In switchdev mode by mlx5_esw_offloads_devlink_port_unregister() -> mlx5_esw_qos_vport_update_parent(). A little later in the same flow, the calls in 1 happen but they are noops. Zooming out a bit, from both mlx5_eswitch_disable_locked() and mlx5_eswitch_disable_sriov() the leaves are destroyed before the nodes, which is the reverse of what should be. For SFs there's no devl_rate_nodes_destroy() call to unparent the affected leaf. Sanitize all of this by: 1. Destroying nodes before leaves in both legacy and switchdev mode. 2. Only removing vport qos from esw_vport_cleanup(), reachable from both legacy and switchdev and also reachable by SF removal. 3. Unexpose mlx5_esw_qos_vport_update_parent(), which becomes internal to qos. 4. Remove the WARN in mlx5_esw_qos_vport_disable(). This also takes care of a theoretical corner case, when mlx5_esw_qos_vport_update_parent() tried to reattach the vport to the original parent on failure, which can fail as well, leaving the vport in a broken state. Signed-off-by: Cosmin Ratiu <[email protected]> Reviewed-by: Carolina Jubran <[email protected]> Signed-off-by: Tariq Toukan <[email protected]> --- .../mellanox/mlx5/core/esw/devlink_port.c | 1 - .../net/ethernet/mellanox/mlx5/core/esw/qos.c | 14 ++++---------- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 19 ++++++++++--------- .../net/ethernet/mellanox/mlx5/core/eswitch.h | 2 -- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index 6e50311faa27..8c27a33f9d7b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -268,7 +268,6 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport) dl_port = vport->dl_port; mlx5_esw_devlink_port_res_unregister(&dl_port->dl_port); - mlx5_esw_qos_vport_update_parent(vport, NULL, NULL); devl_rate_leaf_destroy(&dl_port->dl_port); devl_port_unregister(&dl_port->dl_port); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c index d04fda4b3778..204f47c99142 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c @@ -1139,18 +1139,10 @@ static void mlx5_esw_qos_vport_disable_locked(struct mlx5_vport *vport) void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport) { struct mlx5_eswitch *esw = vport->dev->priv.eswitch; - struct mlx5_esw_sched_node *parent; lockdep_assert_held(&esw->state_lock); esw_qos_lock(esw); - if (!vport->qos.sched_node) - goto unlock; - - parent = vport->qos.sched_node->parent; - WARN(parent, "Disabling QoS on port before detaching it from node"); - mlx5_esw_qos_vport_disable_locked(vport); -unlock: esw_qos_unlock(esw); } @@ -1866,8 +1858,10 @@ int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv, return 0; } -int mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent, - struct netlink_ext_ack *extack) +static int +mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport, + struct mlx5_esw_sched_node *parent, + struct netlink_ext_ack *extack) { struct mlx5_eswitch *esw = vport->dev->priv.eswitch; int err = 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index a0e2ca87b8d8..b67f15a8f766 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1990,6 +1990,13 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) esw->esw_funcs.num_vfs, esw->esw_funcs.num_ec_vfs, esw->enabled_vports); mlx5_eswitch_invalidate_wq(esw); + + if (esw->mode == MLX5_ESWITCH_OFFLOADS) { + struct devlink *devlink = priv_to_devlink(esw->dev); + + devl_rate_nodes_destroy(devlink); + } + mlx5_esw_reps_block(esw); if (!mlx5_core_is_ecpf(esw->dev)) { @@ -2003,12 +2010,6 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) } mlx5_esw_reps_unblock(esw); - - if (esw->mode == MLX5_ESWITCH_OFFLOADS) { - struct devlink *devlink = priv_to_devlink(esw->dev); - - devl_rate_nodes_destroy(devlink); - } /* Destroy legacy fdb when disabling sriov in legacy mode. */ if (esw->mode == MLX5_ESWITCH_LEGACY) mlx5_eswitch_disable_locked(esw); @@ -2039,6 +2040,9 @@ void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw) esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS", esw->esw_funcs.num_vfs, esw->esw_funcs.num_ec_vfs, esw->enabled_vports); + if (esw->mode == MLX5_ESWITCH_OFFLOADS) + devl_rate_nodes_destroy(devlink); + if (esw->fdb_table.flags & MLX5_ESW_FDB_CREATED) { esw->fdb_table.flags &= ~MLX5_ESW_FDB_CREATED; if (esw->mode == MLX5_ESWITCH_OFFLOADS) @@ -2047,9 +2051,6 @@ void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw) esw_legacy_disable(esw); mlx5_esw_acls_ns_cleanup(esw); } - - if (esw->mode == MLX5_ESWITCH_OFFLOADS) - devl_rate_nodes_destroy(devlink); } void mlx5_eswitch_disable(struct mlx5_eswitch *esw) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index fea72b1dedab..140343f2b913 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -482,8 +482,6 @@ int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw, u16 vport_num, bool setting); int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, u16 vport, u32 max_rate, u32 min_rate); -int mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *node, - struct netlink_ext_ack *extack); int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting); int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting); int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw, -- 2.44.0

