Merge branch 'devlink-add-generic-device-max_sfs-parameter'

Tariq Toukan says:

====================
devlink: add generic device max_sfs parameter

This series by Nikolay introduces a new generic devlink device
parameter, max_sfs, to control the number of light-weight NIC
subfunctions (SFs) that can be created on a device.

The first patch adds the generic devlink parameter and infrastructure
support.
The second patch implements support for the parameter in the mlx5
driver.

With this addition, users can enable or disable SF creation directly via
devlink, without relying on external vendor-specific tools.
====================

Link: https://patch.msgid.link/20260806073037.3001886-1-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-08-11 18:06:34 -07:00
5 changed files with 143 additions and 4 deletions

View File

@@ -165,3 +165,9 @@ own name.
- u32
- Controls the maximum number of MAC address filters that can be assigned
to a Virtual Function (VF).
* - ``max_sfs``
- u32
- The maximum number of subfunctions which can be created on the device.
Modifying this parameter may require a device restart and PCI bus
rescanning because the BAR layout may change. A value of 0 disables
subfunction creation.

View File

@@ -45,8 +45,13 @@ Parameters
- The range is between 1 and a device-specific max.
- Applies to each physical function (PF) independently, if the device
supports it. Otherwise, it applies symmetrically to all PFs.
* - ``max_sfs``
- permanent
- The range is between 0 and a device-specific max.
- Applies to each physical function (PF) independently.
Note: permanent parameters such as ``enable_sriov`` and ``total_vfs`` require FW reset to take effect
Note: permanent parameters such as ``enable_sriov``, ``total_vfs`` and ``max_sfs``
require FW reset to take effect
.. code-block:: bash

View File

@@ -68,7 +68,9 @@ struct mlx5_ifc_mnvda_reg_bits {
struct mlx5_ifc_nv_global_pci_conf_bits {
u8 sriov_valid[0x1];
u8 reserved_at_1[0x10];
u8 reserved_at_1[0xa];
u8 per_pf_num_sf[0x1];
u8 reserved_at_c[0x5];
u8 per_pf_total_vf[0x1];
u8 reserved_at_12[0xe];
@@ -93,9 +95,11 @@ struct mlx5_ifc_nv_global_pci_cap_bits {
};
struct mlx5_ifc_nv_pf_pci_conf_bits {
u8 reserved_at_0[0x9];
u8 log_sf_bar_size[0x8];
u8 pf_total_sf_en[0x1];
u8 pf_total_vf_en[0x1];
u8 reserved_at_a[0x16];
u8 reserved_at_a[0x6];
u8 total_sf[0x10];
u8 reserved_at_20[0x20];
@@ -158,6 +162,8 @@ struct mlx5_ifc_nv_sw_accelerate_conf_bits {
#define MLX5_GET_CFG_HDR_LEN(_mnvda_ptr) \
MLX5_GET(mnvda_reg, _mnvda_ptr, configuration_item_header.length)
#define MLX5_DEFAULT_LOG_SF_BAR_SIZE 12
static int mlx5_nv_param_read(struct mlx5_core_dev *dev, void *mnvda,
size_t len)
{
@@ -755,6 +761,115 @@ static int mlx5_devlink_total_vfs_validate(struct devlink *devlink, u32 id,
return 0;
}
static int mlx5_devlink_max_sfs_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
void *data;
int err;
err = mlx5_nv_param_read_global_pci_conf(dev, mnvda, sizeof(mnvda));
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed to read global PCI configuration");
return err;
}
data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
if (!MLX5_GET(nv_global_pci_conf, data, per_pf_num_sf)) {
ctx->val.vu32 = 0;
return 0;
}
memset(mnvda, 0, sizeof(mnvda));
err = mlx5_nv_param_read_per_host_pf_conf(dev, mnvda, sizeof(mnvda));
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to read PF configuration");
return err;
}
data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
if (MLX5_GET(nv_pf_pci_conf, data, pf_total_sf_en))
ctx->val.vu32 = MLX5_GET(nv_pf_pci_conf, data, total_sf);
else
ctx->val.vu32 = 0;
return 0;
}
static int mlx5_devlink_max_sfs_validate(struct devlink *devlink, u32 id,
union devlink_param_value *val,
struct netlink_ext_ack *extack)
{
if (val->vu32 > U16_MAX) {
NL_SET_ERR_MSG_FMT_MOD(extack,
"Max SFs allowed value is %u", U16_MAX);
return -EINVAL;
}
return 0;
}
static int mlx5_devlink_max_sfs_set(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
void *data;
int err;
/* we don't explicitly disable per_pf_num_sf when max_sfs is 0 because
* another PF may be using SFs
*/
if (ctx->val.vu32) {
err = mlx5_nv_param_read_global_pci_conf(dev, mnvda,
sizeof(mnvda));
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed to read global PCI configuration");
return err;
}
data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
/* always enable per_pf_num_sf because another PF may use SFs */
MLX5_SET(nv_global_pci_conf, data, per_pf_num_sf, 1);
err = mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed to change per_pf_num_sf global PCI configuration");
return err;
}
memset(mnvda, 0, sizeof(mnvda));
}
err = mlx5_nv_param_read_per_host_pf_conf(dev, mnvda, sizeof(mnvda));
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to read PF configuration");
return err;
}
data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
MLX5_SET(nv_pf_pci_conf, data, log_sf_bar_size,
ctx->val.vu32 ? MLX5_DEFAULT_LOG_SF_BAR_SIZE : 0);
MLX5_SET(nv_pf_pci_conf, data, pf_total_sf_en, !!ctx->val.vu32);
MLX5_SET(nv_pf_pci_conf, data, total_sf, ctx->val.vu32);
err = mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed to change PF PCI configuration");
return err;
}
NL_SET_ERR_MSG_MOD(extack,
"Modifying max_sfs requires a FW reset and PCI bus rescan");
return 0;
}
static const struct devlink_param mlx5_nv_param_devlink_params[] = {
DEVLINK_PARAM_GENERIC(ENABLE_SRIOV, BIT(DEVLINK_PARAM_CMODE_PERMANENT),
mlx5_devlink_enable_sriov_get,
@@ -763,6 +878,10 @@ static const struct devlink_param mlx5_nv_param_devlink_params[] = {
mlx5_devlink_total_vfs_get,
mlx5_devlink_total_vfs_set,
mlx5_devlink_total_vfs_validate),
DEVLINK_PARAM_GENERIC(MAX_SFS, BIT(DEVLINK_PARAM_CMODE_PERMANENT),
mlx5_devlink_max_sfs_get,
mlx5_devlink_max_sfs_set,
mlx5_devlink_max_sfs_validate),
DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_CQE_COMPRESSION_TYPE,
"cqe_compress_type", DEVLINK_PARAM_TYPE_STRING,
BIT(DEVLINK_PARAM_CMODE_PERMANENT),

View File

@@ -554,6 +554,7 @@ enum devlink_param_generic_id {
DEVLINK_PARAM_GENERIC_ID_TOTAL_VFS,
DEVLINK_PARAM_GENERIC_ID_NUM_DOORBELLS,
DEVLINK_PARAM_GENERIC_ID_MAX_MAC_PER_VF,
DEVLINK_PARAM_GENERIC_ID_MAX_SFS,
/* add new param generic ids above here*/
__DEVLINK_PARAM_GENERIC_ID_MAX,
@@ -627,6 +628,9 @@ enum devlink_param_generic_id {
#define DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_NAME "max_mac_per_vf"
#define DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_TYPE DEVLINK_PARAM_TYPE_U32
#define DEVLINK_PARAM_GENERIC_MAX_SFS_NAME "max_sfs"
#define DEVLINK_PARAM_GENERIC_MAX_SFS_TYPE DEVLINK_PARAM_TYPE_U32
#define DEVLINK_PARAM_GENERIC(_id, _cmodes, _get, _set, _validate) \
{ \
.id = DEVLINK_PARAM_GENERIC_ID_##_id, \

View File

@@ -117,6 +117,11 @@ static const struct devlink_param devlink_param_generic[] = {
.name = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_NAME,
.type = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_TYPE,
},
{
.id = DEVLINK_PARAM_GENERIC_ID_MAX_SFS,
.name = DEVLINK_PARAM_GENERIC_MAX_SFS_NAME,
.type = DEVLINK_PARAM_GENERIC_MAX_SFS_TYPE,
},
};
static int devlink_param_generic_verify(const struct devlink_param *param)