]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net/mlx5: Add satellite PF vport support
authorMoshe Shemesh <moshe@nvidia.com>
Thu, 21 May 2026 11:08:32 +0000 (14:08 +0300)
committerJakub Kicinski <kuba@kernel.org>
Mon, 25 May 2026 20:48:51 +0000 (13:48 -0700)
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 <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20260521110843.367329-2-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c
drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h

index 250af09b5af235b202b9080200fa22c8a9896b54..ca249b50f830a5245beb41ec46e6218167fd757b 100644 (file)
@@ -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)] = {};
index 8a79764345e7e3521a79dd61c2d4bd61154a8175..0730f0c883fe44b82ddc88c1fa13c9a9ac09e5e2 100644 (file)
@@ -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;
 }
index 310afb40cd4768a80e016e3043cbbd2561650e66..921ef53dc074fdf75fea9dc26037d5c94ca0e96f 100644 (file)
@@ -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);
 
index c69a3d50d333b0e4bef81d4e449b9b1e08728d32..2f5a6b390ffb53d5691a353ab5ce79475dc516d2 100644 (file)
@@ -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)