]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net/mlx5: Use v1 response layout for query_esw_functions
authorMoshe Shemesh <moshe@nvidia.com>
Mon, 18 May 2026 07:13:50 +0000 (10:13 +0300)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 21 May 2026 10:11:59 +0000 (12:11 +0200)
Use the v1 response layout for the query_esw_functions command when
supported by the device. When query_host_net_function_v1 capability is
set, use MLX5_QUERY_ESW_FUNC_OP_MOD_LAYOUT_V1 to retrieve parameters
for multiple network functions, allocating the output buffer according
to query_host_net_function_num_max. Validate that firmware does not
return more entries than the allocated buffer.

The v1 layout reports vhca_state instead of the legacy host_pf_disabled
bit. PFs transition through ALLOCATED, ACTIVE, and IN_USE states (they
do not use TEARDOWN_REQUEST as SFs do). When the ECPF calls disable_hca,
firmware resets the PF and moves it to ALLOCATED. When the ECPF calls
enable_hca, the PF moves to ACTIVE, and once the PF driver enables it,
it reaches IN_USE. The PF is only fully operational in IN_USE, so
pf_disabled is derived as vhca_state != IN_USE, equivalent to the legacy
host_pf_disabled bit.

The mlx5_esw_get_host_pf_info() helper abstracts parsing the command
output in both legacy and new formats, so callers do not need to handle
the different layouts.

Signed-off-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20260518071356.345723-3-tariqt@nvidia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/sriov.c

index 861e79ddb48979e1ebae711b32ce21e0428a5120..8b62dde7eb706bb352189de5207c81c411111d21 100644 (file)
@@ -1063,11 +1063,28 @@ static int eswitch_vport_event(struct notifier_block *nb,
  */
 const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
 {
-       int outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out);
+       bool net_func_v1 = MLX5_CAP_GEN(dev, query_host_net_function_v1);
        u32 in[MLX5_ST_SZ_DW(query_esw_functions_in)] = {};
+       int alloc_entries;
+       int outlen;
        u32 *out;
        int err;
 
+       if (net_func_v1) {
+               alloc_entries = MLX5_CAP_GEN(dev,
+                                            query_host_net_function_num_max);
+               alloc_entries = max(alloc_entries, 1);
+               MLX5_SET(query_esw_functions_in, in, op_mod,
+                        MLX5_QUERY_ESW_FUNC_OP_MOD_LAYOUT_V1);
+               outlen = MLX5_BYTE_OFF(query_esw_functions_out,
+                                      net_function_params) +
+                        alloc_entries * MLX5_UN_SZ_BYTES(net_function_params);
+               outlen = max_t(int, outlen,
+                              MLX5_ST_SZ_BYTES(query_esw_functions_out));
+       } else {
+               outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out);
+       }
+
        out = kvzalloc(outlen, GFP_KERNEL);
        if (!out)
                return ERR_PTR(-ENOMEM);
@@ -1076,9 +1093,25 @@ const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
                 MLX5_CMD_OP_QUERY_ESW_FUNCTIONS);
 
        err = mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
-       if (!err)
-               return out;
+       if (err)
+               goto free;
+
+       if (net_func_v1) {
+               int num_entries;
+
+               num_entries = MLX5_GET(query_esw_functions_out, out,
+                                      net_function_num);
+               if (num_entries > alloc_entries) {
+                       mlx5_core_warn(dev, "Got %d entries, max expected %d\n",
+                                      num_entries, alloc_entries);
+                       err = -EINVAL;
+                       goto free;
+               }
+       }
+
+       return out;
 
+free:
        kvfree(out);
        return ERR_PTR(err);
 }
@@ -1100,12 +1133,55 @@ mlx5_esw_host_pf_from_host_params(const void *entry)
        };
 }
 
-struct mlx5_esw_pf_info mlx5_esw_get_host_pf_info(const u32 *out)
+static struct mlx5_esw_pf_info
+mlx5_esw_host_pf_from_net_func_params(const u8 *entry, int num_entries)
+{
+       int i;
+
+       for (i = 0; i < num_entries; i++) {
+               int pf_type, state;
+
+               pf_type = MLX5_GET(network_function_params, entry, pci_pf_type);
+               if (pf_type != MLX5_PCI_PF_TYPE_EXTERNAL_HOST_PF) {
+                       entry += MLX5_UN_SZ_BYTES(net_function_params);
+                       continue;
+               }
+
+               state = MLX5_GET(network_function_params, entry, vhca_state);
+
+               return (struct mlx5_esw_pf_info) {
+                       .pf_disabled = state != MLX5_VHCA_STATE_IN_USE,
+                       .num_of_vfs = MLX5_GET(network_function_params,
+                                              entry, pci_num_vfs),
+                       .total_vfs = MLX5_GET(network_function_params,
+                                             entry, pci_total_vfs),
+                       .host_number = MLX5_GET(network_function_params,
+                                               entry, host_number),
+               };
+       }
+
+       /* No external host PF entry found */
+       return (struct mlx5_esw_pf_info) {
+               .pf_not_exist = true,
+               .pf_disabled = true,
+       };
+}
+
+struct mlx5_esw_pf_info
+mlx5_esw_get_host_pf_info(struct mlx5_core_dev *dev, const u32 *out)
 {
        const void *entry;
 
        entry = MLX5_ADDR_OF(query_esw_functions_out, out, net_function_params);
 
+       if (MLX5_CAP_GEN(dev, query_host_net_function_v1)) {
+               int num_entries = MLX5_GET(query_esw_functions_out, out,
+                                          net_function_num);
+
+               return mlx5_esw_host_pf_from_net_func_params(entry,
+                                                            num_entries);
+       }
+
        return mlx5_esw_host_pf_from_host_params(entry);
 }
 
@@ -1121,7 +1197,7 @@ static int mlx5_esw_host_functions_enabled_query(struct mlx5_eswitch *esw)
        if (IS_ERR(query_host_out))
                return PTR_ERR(query_host_out);
 
-       host_pf_info = mlx5_esw_get_host_pf_info(query_host_out);
+       host_pf_info = mlx5_esw_get_host_pf_info(esw->dev, query_host_out);
        esw->esw_funcs.host_funcs_disabled = host_pf_info.pf_not_exist;
 
        kvfree(query_host_out);
@@ -1561,7 +1637,7 @@ mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, int num_vfs)
        if (IS_ERR(out))
                return;
 
-       host_pf_info = mlx5_esw_get_host_pf_info(out);
+       host_pf_info = mlx5_esw_get_host_pf_info(esw->dev, out);
        esw->esw_funcs.num_vfs = host_pf_info.num_of_vfs;
        if (mlx5_core_ec_sriov_enabled(esw->dev))
                esw->esw_funcs.num_ec_vfs = num_vfs;
index cfaae59a6e7cfdca0eb73b34b19de0fbe41202bb..a5f832ed22515de4c67d703b658bd0750444a876 100644 (file)
@@ -657,7 +657,8 @@ bool mlx5_esw_multipath_prereq(struct mlx5_core_dev *dev0,
                               struct mlx5_core_dev *dev1);
 
 const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev);
-struct mlx5_esw_pf_info mlx5_esw_get_host_pf_info(const u32 *out);
+struct mlx5_esw_pf_info mlx5_esw_get_host_pf_info(struct mlx5_core_dev *dev,
+                                                 const u32 *out);
 int mlx5_esw_host_pf_enable_hca(struct mlx5_core_dev *dev);
 int mlx5_esw_host_pf_disable_hca(struct mlx5_core_dev *dev);
 
@@ -986,7 +987,7 @@ static inline const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
 }
 
 static inline struct mlx5_esw_pf_info
-mlx5_esw_get_host_pf_info(const u32 *out)
+mlx5_esw_get_host_pf_info(struct mlx5_core_dev *dev, const u32 *out)
 {
        return (struct mlx5_esw_pf_info) {};
 }
index 217c2fe6b6903cd245a86823c8785a1984e2e4d4..acbc37b0530856af62112102e5be56c0e02f132a 100644 (file)
@@ -3716,7 +3716,7 @@ static void esw_vfs_changed_event_handler(struct mlx5_eswitch *esw)
        if (IS_ERR(out))
                return;
 
-       host_pf_info = mlx5_esw_get_host_pf_info(out);
+       host_pf_info = mlx5_esw_get_host_pf_info(esw->dev, out);
        new_num_vfs = host_pf_info.num_of_vfs;
 
        if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_info.pf_disabled)
@@ -3832,7 +3832,7 @@ static int mlx5_esw_host_number_init(struct mlx5_eswitch *esw)
                return PTR_ERR(query_host_out);
 
        /* Mark non local controller with non zero controller number. */
-       host_pf_info = mlx5_esw_get_host_pf_info(query_host_out);
+       host_pf_info = mlx5_esw_get_host_pf_info(esw->dev, query_host_out);
        esw->offloads.host_number = host_pf_info.host_number;
        kvfree(query_host_out);
        return 0;
@@ -4988,7 +4988,7 @@ int mlx5_devlink_pf_port_fn_state_get(struct devlink_port *port,
        if (IS_ERR(query_out))
                return PTR_ERR(query_out);
 
-       host_pf_info = mlx5_esw_get_host_pf_info(query_out);
+       host_pf_info = mlx5_esw_get_host_pf_info(vport->dev, query_out);
 
        *opstate = host_pf_info.pf_disabled ?
                        DEVLINK_PORT_FN_OPSTATE_DETACHED :
index 79f76c456d7257a80fae7d3a8df3f61cc0cedc62..0770b5d99c5dbcb5f9b8c82b7983b893d49d3e6b 100644 (file)
@@ -285,7 +285,7 @@ static u16 mlx5_get_max_vfs(struct mlx5_core_dev *dev)
                 */
                if (IS_ERR(out))
                        goto done;
-               host_pf_info = mlx5_esw_get_host_pf_info(out);
+               host_pf_info = mlx5_esw_get_host_pf_info(dev, out);
                host_total_vfs = host_pf_info.total_vfs;
                kvfree(out);
                return host_total_vfs;