From: Moshe Shemesh Date: Thu, 21 May 2026 11:08:32 +0000 (+0300) Subject: net/mlx5: Add satellite PF vport support X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ed9671b8bd4f084b9b2798d3892c3c83f3c1010c;p=thirdparty%2Fkernel%2Flinux.git net/mlx5: Add satellite PF vport support Discover satellite PFs from query_esw_functions output and allocate eswitch vports for them. For each satellite PF, create a vport via the CREATE_ESW_VPORT command using its vhca_id and allocate it in the eswitch vport table. When enabling switchdev mode, the ECPF acting as the eswitch manager activates each satellite PF with enable_hca, loads its vport and adds a representor. Since satellite PF devlink ports are registered in a later patch, guard mlx5_esw_offloads_devlink_port() against vports with no devlink port to avoid NULL dereference during representor attach. Signed-off-by: Moshe Shemesh Signed-off-by: Tariq Toukan Link: https://patch.msgid.link/20260521110843.367329-2-tariqt@nvidia.com Signed-off-by: Jakub Kicinski --- diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c index 250af09b5af23..ca249b50f830a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c @@ -23,7 +23,7 @@ int mlx5_esw_adj_vport_modify(struct mlx5_core_dev *dev, u16 vport, return mlx5_cmd_exec_in(dev, modify_vport_state, in); } -static void mlx5_esw_destroy_esw_vport(struct mlx5_core_dev *dev, u16 vport) +void mlx5_esw_destroy_esw_vport(struct mlx5_core_dev *dev, u16 vport) { u32 in[MLX5_ST_SZ_DW(destroy_esw_vport_in)] = {}; @@ -34,8 +34,8 @@ static void mlx5_esw_destroy_esw_vport(struct mlx5_core_dev *dev, u16 vport) mlx5_cmd_exec_in(dev, destroy_esw_vport, in); } -static int mlx5_esw_create_esw_vport(struct mlx5_core_dev *dev, u16 vhca_id, - u16 *vport_num) +int mlx5_esw_create_esw_vport(struct mlx5_core_dev *dev, u16 vhca_id, + u16 *vport_num) { u32 out[MLX5_ST_SZ_DW(create_esw_vport_out)] = {}; u32 in[MLX5_ST_SZ_DW(create_esw_vport_in)] = {}; 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 8a79764345e7e..0730f0c883fe4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -253,5 +253,10 @@ struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u1 struct mlx5_vport *vport; vport = mlx5_eswitch_get_vport(esw, vport_num); - return IS_ERR(vport) ? ERR_CAST(vport) : &vport->dl_port->dl_port; + if (IS_ERR(vport)) + return ERR_CAST(vport); + if (!vport->dl_port) + return ERR_PTR(-ENODEV); + + return &vport->dl_port->dl_port; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 310afb40cd476..921ef53dc074f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1538,8 +1538,11 @@ int mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, enum mlx5_eswitch_vport_event enabled_events) { + struct mlx5_esw_functions *esw_funcs = &esw->esw_funcs; bool pf_needed; + u16 vport_num; int ret; + int i; pf_needed = mlx5_core_is_ecpf_esw_manager(esw->dev) || esw->mode == MLX5_ESWITCH_LEGACY; @@ -1569,14 +1572,14 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, /* Enable ECVF vports */ if (mlx5_core_ec_sriov_enabled(esw->dev)) { ret = mlx5_eswitch_load_ec_vf_vports(esw, - esw->esw_funcs.num_ec_vfs, + esw_funcs->num_ec_vfs, enabled_events); if (ret) goto ec_vf_err; } /* Enable VF vports */ - ret = mlx5_eswitch_load_vf_vports(esw, esw->esw_funcs.num_vfs, + ret = mlx5_eswitch_load_vf_vports(esw, esw_funcs->num_vfs, enabled_events); if (ret) goto vf_err; @@ -1586,13 +1589,36 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, if (ret) goto unload_vf_vports; + /* Enable satellite PF vports */ + for (i = 0; i < esw_funcs->num_spfs; i++) { + vport_num = esw_funcs->spfs[i].vport_num; + + ret = mlx5_eswitch_load_pf_vf_vport(esw, vport_num, + enabled_events); + if (ret) + goto spf_err; + + ret = mlx5_esw_pf_enable_hca(esw->dev, vport_num); + if (ret) { + mlx5_eswitch_unload_pf_vf_vport(esw, vport_num); + goto spf_err; + } + } + return 0; +spf_err: + while (i-- > 0) { + vport_num = esw_funcs->spfs[i].vport_num; + mlx5_esw_pf_disable_hca(esw->dev, vport_num); + mlx5_eswitch_unload_pf_vf_vport(esw, vport_num); + } + mlx5_eswitch_unload_adj_vf_vports(esw); unload_vf_vports: - mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs); + mlx5_eswitch_unload_vf_vports(esw, esw_funcs->num_vfs); vf_err: if (mlx5_core_ec_sriov_enabled(esw->dev)) - mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs); + mlx5_eswitch_unload_ec_vf_vports(esw, esw_funcs->num_ec_vfs); ec_vf_err: if (mlx5_ecpf_vport_exists(esw->dev)) mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF); @@ -1610,13 +1636,22 @@ pf_hca_err: */ void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw) { + struct mlx5_esw_functions *esw_funcs = &esw->esw_funcs; + u16 vport_num; + int i; + + for (i = 0; i < esw_funcs->num_spfs; i++) { + vport_num = esw_funcs->spfs[i].vport_num; + mlx5_esw_pf_disable_hca(esw->dev, vport_num); + mlx5_eswitch_unload_pf_vf_vport(esw, vport_num); + } + mlx5_eswitch_unload_adj_vf_vports(esw); - mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs); + mlx5_eswitch_unload_vf_vports(esw, esw_funcs->num_vfs); if (mlx5_core_ec_sriov_enabled(esw->dev)) - mlx5_eswitch_unload_ec_vf_vports(esw, - esw->esw_funcs.num_ec_vfs); + mlx5_eswitch_unload_ec_vf_vports(esw, esw_funcs->num_ec_vfs); if (mlx5_ecpf_vport_exists(esw->dev)) { mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF); @@ -2086,11 +2121,105 @@ void mlx5_esw_vport_free(struct mlx5_eswitch *esw, struct mlx5_vport *vport) kfree(vport); } +static void mlx5_esw_spfs_cleanup(struct mlx5_eswitch *esw) +{ + struct mlx5_esw_functions *esw_funcs = &esw->esw_funcs; + int i; + + for (i = 0; i < esw_funcs->num_spfs; i++) + mlx5_esw_destroy_esw_vport(esw->dev, + esw_funcs->spfs[i].vport_num); + + kfree(esw_funcs->spfs); + esw_funcs->spfs = NULL; + esw_funcs->num_spfs = 0; +} + +static int mlx5_esw_spfs_init(struct mlx5_eswitch *esw) +{ + struct mlx5_esw_functions *esw_funcs = &esw->esw_funcs; + struct mlx5_core_dev *dev = esw->dev; + int num_entries; + const u8 *entry; + const u32 *out; + int err = 0; + int pf_type; + u16 vhca_id; + int i; + + if (!MLX5_CAP_GEN(dev, query_host_net_function_v1)) + return 0; + + out = mlx5_esw_query_functions(dev); + if (IS_ERR(out)) + return PTR_ERR(out); + + num_entries = MLX5_GET(query_esw_functions_out, out, net_function_num); + if (!num_entries) + goto out_free; + + esw_funcs->spfs = kcalloc(num_entries, sizeof(*esw_funcs->spfs), + GFP_KERNEL); + if (!esw_funcs->spfs) { + err = -ENOMEM; + goto out_free; + } + + entry = MLX5_ADDR_OF(query_esw_functions_out, out, net_function_params); + + for (i = 0; i < num_entries; i++) { + u16 vport_num; + + pf_type = MLX5_GET(network_function_params, entry, pci_pf_type); + if (pf_type != MLX5_PCI_PF_TYPE_SATELLITE_PF) { + entry += MLX5_UN_SZ_BYTES(net_function_params); + continue; + } + + if (!MLX5_GET(network_function_params, entry, + esw_vport_manual)) { + esw_warn(dev, "Satellite PF without esw_vport_manual is not supported\n"); + entry += MLX5_UN_SZ_BYTES(net_function_params); + continue; + } + + vhca_id = MLX5_GET(network_function_params, entry, vhca_id); + + err = mlx5_esw_create_esw_vport(dev, vhca_id, &vport_num); + if (err) { + esw_warn(dev, "Failed to create satellite PF vport for vhca_id 0x%x, err %d\n", + vhca_id, err); + goto spfs_cleanup; + } + + esw_funcs->spfs[esw_funcs->num_spfs].vport_num = vport_num; + esw_funcs->spfs[esw_funcs->num_spfs].vhca_id = vhca_id; + esw_funcs->num_spfs++; + + entry += MLX5_UN_SZ_BYTES(net_function_params); + } + + if (!esw_funcs->num_spfs) { + kfree(esw_funcs->spfs); + esw_funcs->spfs = NULL; + } + + kvfree(out); + return 0; + +spfs_cleanup: + mlx5_esw_spfs_cleanup(esw); +out_free: + kvfree(out); + return err; +} + static void mlx5_esw_vports_cleanup(struct mlx5_eswitch *esw) { struct mlx5_vport *vport; unsigned long i; + mlx5_esw_spfs_cleanup(esw); mlx5_esw_for_each_vport(esw, i, vport) mlx5_esw_vport_free(esw, vport); xa_destroy(&esw->vports); @@ -2144,6 +2273,22 @@ static int mlx5_esw_vports_init(struct mlx5_eswitch *esw) idx++; } + err = mlx5_esw_spfs_init(esw); + if (err) + goto err; + + for (i = 0; i < esw->esw_funcs.num_spfs; i++) { + struct mlx5_vport *vport; + u16 vport_num; + + vport_num = esw->esw_funcs.spfs[i].vport_num; + err = mlx5_esw_vport_alloc(esw, idx++, vport_num); + if (err) + goto err; + vport = mlx5_eswitch_get_vport(esw, vport_num); + vport->vhca_id = esw->esw_funcs.spfs[i].vhca_id; + } + if (mlx5_core_ec_sriov_enabled(esw->dev)) { int ec_vf_base_num = mlx5_core_ec_vf_vport_base(dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index c69a3d50d333b..2f5a6b390ffb5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -350,11 +350,18 @@ struct mlx5_host_work { void (*func)(struct mlx5_eswitch *esw); }; +struct mlx5_esw_spf { + u16 vport_num; + u16 vhca_id; +}; + struct mlx5_esw_functions { struct mlx5_nb nb; bool host_funcs_disabled; u16 num_vfs; u16 num_ec_vfs; + struct mlx5_esw_spf *spfs; + int num_spfs; }; enum { @@ -667,6 +674,9 @@ void mlx5_esw_adjacent_vhcas_setup(struct mlx5_eswitch *esw); void mlx5_esw_adjacent_vhcas_cleanup(struct mlx5_eswitch *esw); int mlx5_esw_adj_vport_modify(struct mlx5_core_dev *dev, u16 vport, bool connect); +int mlx5_esw_create_esw_vport(struct mlx5_core_dev *dev, u16 vhca_id, + u16 *vport_num); +void mlx5_esw_destroy_esw_vport(struct mlx5_core_dev *dev, u16 vport); #define MLX5_DEBUG_ESWITCH_MASK BIT(3)