From: Moshe Shemesh 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. This change does not introduce new functionality, but enables the existing mlx5_esw_query_functions() callers to retrieve host PF information with the new layout as well. 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 Signed-off-by: Tariq Toukan --- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 88 +++++++++++++++++-- .../net/ethernet/mellanox/mlx5/core/eswitch.h | 5 +- .../mellanox/mlx5/core/eswitch_offloads.c | 6 +- .../net/ethernet/mellanox/mlx5/core/sriov.c | 2 +- 4 files changed, 89 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 861e79ddb489..8b62dde7eb70 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -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; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index cfaae59a6e7c..a5f832ed2251 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -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) {}; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 217c2fe6b690..acbc37b05308 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -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 : diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index 79f76c456d72..0770b5d99c5d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -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; -- 2.44.0