Add configuration parameters setting through devlink.
Each device registers supported configuration parameters table.
Each parameter can be either generic or driver specific.
The user can retrieve data on these parameters by "devlink param show"
command and can set new value to a parameter by "devlink param set"
command.
The parameters can be set in different configuration modes:
runtime - set while driver is running, no reset required.
driverinit - applied while driver initializes, requires restart
driver by devlink reload command.
permanent - written to device's non-volatile memory, hard reset required.
The patches at the end of the patchset introduce few params that are using
the introduced infrastructure on mlx4 and bnxt.
Command examples and output:
# devlink dev param show
pci/0000:81:00.0:
name internal_error_reset type generic
values:
cmode runtime value true
cmode driverinit value true
name max_macs type generic
values:
cmode driverinit value 128
name enable_64b_cqe_eqe type driver-specific
values:
cmode driverinit value true
name enable_4k_uar type driver-specific
values:
cmode driverinit value false
# devlink dev param set pci/0000:81:00.0 name internal_error_reset cmode runtime value false
# devlink dev param show pci/0000:81:00.0 name internal_error_reset
pci/0000:81:00.0:
name internal_error_reset type generic
values:
cmode runtime value false
cmode driverinit value true
Moshe Shemesh (8):
devlink: Add devlink_param register and unregister
devlink: Add param get command
devlink: Add param set command
devlink: Add support for get/set driverinit value
devlink: Add devlink notifications support for params
devlink: Add generic parameters internal_err_reset and max_macs
mlx4: Add mlx4 initial parameters table and register it
mlx4: Add support for devlink reload and load driverinit values
Vasundhara Volam (2):
devlink: Add enable_sriov boolean generic parameter
bnxt_en: Add bnxt_en initial params table and register it.
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 121 +++-
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h | 15 +
drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 13 +
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c | 9 +-
drivers/net/ethernet/mellanox/mlx4/catas.c | 2 +-
drivers/net/ethernet/mellanox/mlx4/main.c | 161 +++++-
drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 +-
include/net/devlink.h | 149 +++++
include/uapi/linux/devlink.h | 24 +
net/core/devlink.c | 675 ++++++++++++++++++++++
10 files changed, 1156 insertions(+), 16 deletions(-)
--
1.8.3.1
"driverinit" configuration mode value is held by devlink to enable
the driver query the value after reload. Two additional functions
added to help the driver get/set the value from/to devlink:
devlink_param_driverinit_value_set() and
devlink_param_driverinit_value_get().
Signed-off-by: Moshe Shemesh <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
include/net/devlink.h | 18 ++++++++++++
net/core/devlink.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 95 insertions(+)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 8806275..3302e43 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -503,6 +503,10 @@ int devlink_params_register(struct devlink *devlink,
void devlink_params_unregister(struct devlink *devlink,
const struct devlink_param *params,
size_t params_count);
+int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
+ union devlink_param_value *init_val);
+int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
+ union devlink_param_value init_val);
#else
@@ -711,6 +715,20 @@ static inline bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
}
+static inline int
+devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
+ union devlink_param_value *init_val)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
+ union devlink_param_value init_val)
+{
+ return -EOPNOTSUPP;
+}
+
#endif
#endif /* _NET_DEVLINK_H_ */
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 0cd7a42..3af08f4 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -2645,6 +2645,17 @@ static int devlink_param_driver_verify(const struct devlink_param *param)
return NULL;
}
+static struct devlink_param_item *
+devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
+{
+ struct devlink_param_item *param_item;
+
+ list_for_each_entry(param_item, param_list, list)
+ if (param_item->param->id == param_id)
+ return param_item;
+ return NULL;
+}
+
static bool
devlink_param_cmode_is_supported(const struct devlink_param *param,
enum devlink_param_cmode cmode)
@@ -3966,6 +3977,72 @@ void devlink_params_unregister(struct devlink *devlink,
}
EXPORT_SYMBOL_GPL(devlink_params_unregister);
+/**
+ * devlink_param_driverinit_value_get - get configuration parameter
+ * value for driver initializing
+ *
+ * @devlink: devlink
+ * @param_id: parameter ID
+ * @init_val: value of parameter in driverinit configuration mode
+ *
+ * This function should be used by the driver to get driverinit
+ * configuration for initialization after reload command.
+ */
+int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
+ union devlink_param_value *init_val)
+{
+ struct devlink_param_item *param_item;
+
+ if (!devlink->ops || !devlink->ops->reload)
+ return -EOPNOTSUPP;
+
+ param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
+ if (!param_item)
+ return -EINVAL;
+
+ if (!param_item->driverinit_value_valid ||
+ !devlink_param_cmode_is_supported(param_item->param,
+ DEVLINK_PARAM_CMODE_DRIVERINIT))
+ return -EOPNOTSUPP;
+
+ *init_val = param_item->driverinit_value;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
+
+/**
+ * devlink_param_driverinit_value_set - set value of configuration
+ * parameter for driverinit
+ * configuration mode
+ *
+ * @devlink: devlink
+ * @param_id: parameter ID
+ * @init_val: value of parameter to set for driverinit configuration mode
+ *
+ * This function should be used by the driver to set driverinit
+ * configuration mode default value.
+ */
+int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
+ union devlink_param_value init_val)
+{
+ struct devlink_param_item *param_item;
+
+ param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
+ if (!param_item)
+ return -EINVAL;
+
+ if (!devlink_param_cmode_is_supported(param_item->param,
+ DEVLINK_PARAM_CMODE_DRIVERINIT))
+ return -EOPNOTSUPP;
+
+ param_item->driverinit_value = init_val;
+ param_item->driverinit_value_valid = true;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
+
static int __init devlink_module_init(void)
{
return genl_register_family(&devlink_nl_family);
--
1.8.3.1
From: Vasundhara Volam <[email protected]>
Create initial devlink parameters table for bnxt_en.
Table consists of a permanent generic parameter.
enable_sriov - Enables Single-Root Input/Output Virtualization(SR-IOV)
characteristic of the device.
Reviewed-by: Jiri Pirko <[email protected]>
Reviewed-by: Michael Chan <[email protected]>
Signed-off-by: Vasundhara Volam <[email protected]>
---
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 121 ++++++++++++++++++++--
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h | 15 +++
drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 13 +++
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c | 9 +-
4 files changed, 147 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
index 402fa32..7bd96ab 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
@@ -21,16 +21,99 @@
#endif /* CONFIG_BNXT_SRIOV */
};
+static const struct bnxt_dl_nvm_param nvm_params[] = {
+ {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
+ BNXT_NVM_SHARED_CFG, 1},
+};
+
+static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
+ int msg_len, union devlink_param_value *val)
+{
+ struct hwrm_nvm_variable_input *req = msg;
+ void *data_addr = NULL, *buf = NULL;
+ struct bnxt_dl_nvm_param nvm_param;
+ int bytesize, idx = 0, rc, i;
+ dma_addr_t data_dma_addr;
+
+ /* Get/Set NVM CFG parameter is supported only on PFs */
+ if (BNXT_VF(bp))
+ return -EPERM;
+
+ for (i = 0; i < ARRAY_SIZE(nvm_params); i++) {
+ if (nvm_params[i].id == param_id) {
+ nvm_param = nvm_params[i];
+ break;
+ }
+ }
+
+ if (nvm_param.dir_type == BNXT_NVM_PORT_CFG)
+ idx = bp->pf.port_id;
+ else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG)
+ idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
+
+ bytesize = roundup(nvm_param.num_bits, BITS_PER_BYTE) / BITS_PER_BYTE;
+ if (nvm_param.num_bits == 1)
+ buf = &val->vbool;
+
+ data_addr = dma_zalloc_coherent(&bp->pdev->dev, bytesize,
+ &data_dma_addr, GFP_KERNEL);
+ if (!data_addr)
+ return -ENOMEM;
+
+ req->data_addr = cpu_to_le64(data_dma_addr);
+ req->data_len = cpu_to_le16(nvm_param.num_bits);
+ req->option_num = cpu_to_le16(nvm_param.offset);
+ req->index_0 = cpu_to_le16(idx);
+ if (idx)
+ req->dimensions = cpu_to_le16(1);
+
+ if (req->req_type == HWRM_NVM_SET_VARIABLE)
+ memcpy(data_addr, buf, bytesize);
+
+ rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
+ if (!rc && req->req_type == HWRM_NVM_GET_VARIABLE)
+ memcpy(buf, data_addr, bytesize);
+
+ dma_free_coherent(&bp->pdev->dev, bytesize, data_addr, data_dma_addr);
+ if (rc)
+ return -EIO;
+ return 0;
+}
+
+static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ struct hwrm_nvm_get_variable_input req = {0};
+ struct bnxt *bp = bnxt_get_bp_from_dl(dl);
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
+ return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
+}
+
+static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ struct hwrm_nvm_set_variable_input req = {0};
+ struct bnxt *bp = bnxt_get_bp_from_dl(dl);
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
+ return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
+}
+
+static const struct devlink_param bnxt_dl_params[] = {
+ DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
+ BIT(DEVLINK_PARAM_CMODE_PERMANENT),
+ bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
+ NULL),
+};
+
int bnxt_dl_register(struct bnxt *bp)
{
struct devlink *dl;
int rc;
- if (!pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV))
- return 0;
-
- if (bp->hwrm_spec_code < 0x10803) {
- netdev_warn(bp->dev, "Firmware does not support SR-IOV E-Switch SWITCHDEV mode.\n");
+ if (bp->hwrm_spec_code < 0x10600) {
+ netdev_warn(bp->dev, "Firmware does not support NVM params");
return -ENOTSUPP;
}
@@ -41,16 +124,34 @@ int bnxt_dl_register(struct bnxt *bp)
}
bnxt_link_bp_to_dl(bp, dl);
- bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
+
+ /* Add switchdev eswitch mode setting, if SRIOV supported */
+ if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
+ bp->hwrm_spec_code > 0x10803)
+ bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
+
rc = devlink_register(dl, &bp->pdev->dev);
if (rc) {
- bnxt_link_bp_to_dl(bp, NULL);
- devlink_free(dl);
netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
- return rc;
+ goto err_dl_free;
+ }
+
+ rc = devlink_params_register(dl, bnxt_dl_params,
+ ARRAY_SIZE(bnxt_dl_params));
+ if (rc) {
+ netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
+ rc);
+ goto err_dl_unreg;
}
return 0;
+
+err_dl_unreg:
+ devlink_unregister(dl);
+err_dl_free:
+ bnxt_link_bp_to_dl(bp, NULL);
+ devlink_free(dl);
+ return rc;
}
void bnxt_dl_unregister(struct bnxt *bp)
@@ -60,6 +161,8 @@ void bnxt_dl_unregister(struct bnxt *bp)
if (!dl)
return;
+ devlink_params_unregister(dl, bnxt_dl_params,
+ ARRAY_SIZE(bnxt_dl_params));
devlink_unregister(dl);
devlink_free(dl);
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
index e92a35d..2f68dc0 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
@@ -33,6 +33,21 @@ static inline void bnxt_link_bp_to_dl(struct bnxt *bp, struct devlink *dl)
}
}
+#define NVM_OFF_ENABLE_SRIOV 401
+
+enum bnxt_nvm_dir_type {
+ BNXT_NVM_SHARED_CFG = 40,
+ BNXT_NVM_PORT_CFG,
+ BNXT_NVM_FUNC_CFG,
+};
+
+struct bnxt_dl_nvm_param {
+ u16 id;
+ u16 offset;
+ u16 dir_type;
+ u16 num_bits;
+};
+
int bnxt_dl_register(struct bnxt *bp);
void bnxt_dl_unregister(struct bnxt *bp);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
index 0fe0ea8..c75d7fa 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
@@ -6201,6 +6201,19 @@ struct hwrm_nvm_install_update_cmd_err {
u8 unused_0[7];
};
+struct hwrm_nvm_variable_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le64 data_addr;
+ __le16 data_len;
+ __le16 option_num;
+ __le16 dimensions;
+ __le16 index_0;
+};
+
/* hwrm_nvm_get_variable_input (size:320b/40B) */
struct hwrm_nvm_get_variable_input {
__le16 req_type;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
index 0745f2d..e31f5d8 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
@@ -543,9 +543,14 @@ int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode)
break;
case DEVLINK_ESWITCH_MODE_SWITCHDEV:
+ if (bp->hwrm_spec_code < 0x10803) {
+ netdev_warn(bp->dev, "FW does not support SRIOV E-Switch SWITCHDEV mode\n");
+ rc = -ENOTSUPP;
+ goto done;
+ }
+
if (pci_num_vf(bp->pdev) == 0) {
- netdev_info(bp->dev,
- "Enable VFs before setting switchdev mode");
+ netdev_info(bp->dev, "Enable VFs before setting switchdev mode");
rc = -EPERM;
goto done;
}
--
1.8.3.1
Create initial parameters table for mlx4.
The table consists of two generic parameters and two driver-specific
parameters.
Generic:
internal_err_reset - Enable reset device on internal errors. This
parameter can be configured on mlx4 either on runtime or during driver
initialization.
max_macs - Max number of MACs per ETH port. For mlx4 this parameter
value range is between 1 and 128. This parameter can be configured on
mlx4 only during driver initialization.
Driver specific:
enable_64b_cqe_eqe - Enable 64 byte CQEs/EQEs when the FW supports it.
This parameter can be configured on mlx4 only during driver
initialization.
enable_4k_uar - Enable using 4K UAR. This parameter can be configured on
mlx4 only during driver initialization.
Register the parameters table on mlx4_init_one() and unregister on
mlx4_remove_one().
Signed-off-by: Moshe Shemesh <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
drivers/net/ethernet/mellanox/mlx4/main.c | 108 +++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 8720147..2445f79 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -177,6 +177,101 @@ struct mlx4_port_config {
static atomic_t pf_loading = ATOMIC_INIT(0);
+static int mlx4_devlink_ierr_reset_get(struct devlink *devlink, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ ctx->val.vbool = !!mlx4_internal_err_reset;
+ return 0;
+}
+
+static int mlx4_devlink_ierr_reset_set(struct devlink *devlink, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ mlx4_internal_err_reset = ctx->val.vbool;
+ return 0;
+}
+
+static int
+mlx4_devlink_max_macs_validate(struct devlink *devlink, u32 id,
+ union devlink_param_value val,
+ struct netlink_ext_ack *extack)
+{
+ u32 value = val.vu32;
+
+ if (value < 1 || value > 128)
+ return -ERANGE;
+
+ if (!is_power_of_2(value)) {
+ NL_SET_ERR_MSG_MOD(extack, "max_macs supported must be power of 2");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+enum mlx4_devlink_param_id {
+ MLX4_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
+ MLX4_DEVLINK_PARAM_ID_ENABLE_64B_CQE_EQE,
+ MLX4_DEVLINK_PARAM_ID_ENABLE_4K_UAR,
+};
+
+static const struct devlink_param mlx4_devlink_params[] = {
+ DEVLINK_PARAM_GENERIC(INT_ERR_RESET,
+ BIT(DEVLINK_PARAM_CMODE_RUNTIME) |
+ BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
+ mlx4_devlink_ierr_reset_get,
+ mlx4_devlink_ierr_reset_set, NULL),
+ DEVLINK_PARAM_GENERIC(MAX_MACS,
+ BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
+ NULL, NULL, mlx4_devlink_max_macs_validate),
+ DEVLINK_PARAM_DRIVER(MLX4_DEVLINK_PARAM_ID_ENABLE_64B_CQE_EQE,
+ "enable_64b_cqe_eqe", DEVLINK_PARAM_TYPE_BOOL,
+ BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
+ NULL, NULL, NULL),
+ DEVLINK_PARAM_DRIVER(MLX4_DEVLINK_PARAM_ID_ENABLE_4K_UAR,
+ "enable_4k_uar", DEVLINK_PARAM_TYPE_BOOL,
+ BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
+ NULL, NULL, NULL),
+};
+
+static void mlx4_devlink_set_init_value(struct devlink *devlink, u32 param_id,
+ union devlink_param_value init_val)
+{
+ struct mlx4_priv *priv = devlink_priv(devlink);
+ struct mlx4_dev *dev = &priv->dev;
+ int err;
+
+ err = devlink_param_driverinit_value_set(devlink, param_id, init_val);
+ if (err)
+ mlx4_warn(dev,
+ "devlink set parameter %u value failed (err = %d)",
+ param_id, err);
+}
+
+static void mlx4_devlink_set_params_init_values(struct devlink *devlink)
+{
+ union devlink_param_value value;
+
+ value.vbool = !!mlx4_internal_err_reset;
+ mlx4_devlink_set_init_value(devlink,
+ DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
+ value);
+
+ value.vu32 = 1UL << log_num_mac;
+ mlx4_devlink_set_init_value(devlink,
+ DEVLINK_PARAM_GENERIC_ID_MAX_MACS, value);
+
+ value.vbool = enable_64b_cqe_eqe;
+ mlx4_devlink_set_init_value(devlink,
+ MLX4_DEVLINK_PARAM_ID_ENABLE_64B_CQE_EQE,
+ value);
+
+ value.vbool = enable_4k_uar;
+ mlx4_devlink_set_init_value(devlink,
+ MLX4_DEVLINK_PARAM_ID_ENABLE_4K_UAR,
+ value);
+}
+
static inline void mlx4_set_num_reserved_uars(struct mlx4_dev *dev,
struct mlx4_dev_cap *dev_cap)
{
@@ -3792,14 +3887,21 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ret = devlink_register(devlink, &pdev->dev);
if (ret)
goto err_persist_free;
-
- ret = __mlx4_init_one(pdev, id->driver_data, priv);
+ ret = devlink_params_register(devlink, mlx4_devlink_params,
+ ARRAY_SIZE(mlx4_devlink_params));
if (ret)
goto err_devlink_unregister;
+ mlx4_devlink_set_params_init_values(devlink);
+ ret = __mlx4_init_one(pdev, id->driver_data, priv);
+ if (ret)
+ goto err_params_unregister;
pci_save_state(pdev);
return 0;
+err_params_unregister:
+ devlink_params_unregister(devlink, mlx4_devlink_params,
+ ARRAY_SIZE(mlx4_devlink_params));
err_devlink_unregister:
devlink_unregister(devlink);
err_persist_free:
@@ -3936,6 +4038,8 @@ static void mlx4_remove_one(struct pci_dev *pdev)
pci_release_regions(pdev);
mlx4_pci_disable_device(dev);
+ devlink_params_unregister(devlink, mlx4_devlink_params,
+ ARRAY_SIZE(mlx4_devlink_params));
devlink_unregister(devlink);
kfree(dev->persist);
devlink_free(devlink);
--
1.8.3.1
Add devlink_param_notify() function to support devlink param notifications.
Add notification call to devlink param set, register and unregister
functions.
Add devlink_param_value_changed() function to enable the driver notify
devlink on value change. Driver should use this function after value was
changed on any configuration mode part to driverinit.
Signed-off-by: Moshe Shemesh <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
include/net/devlink.h | 7 +++++++
include/uapi/linux/devlink.h | 2 ++
net/core/devlink.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 59 insertions(+)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 3302e43..792edaa 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -507,6 +507,7 @@ int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
union devlink_param_value *init_val);
int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
union devlink_param_value init_val);
+void devlink_param_value_changed(struct devlink *devlink, u32 param_id);
#else
@@ -729,6 +730,12 @@ static inline bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
return -EOPNOTSUPP;
}
+static inline void
+devlink_param_value_changed(struct devlink *devlink, u32 param_id)
+{
+ return -EOPNOTSUPP;
+}
+
#endif
#endif /* _NET_DEVLINK_H_ */
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index ea0623e..68641fb 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -80,6 +80,8 @@ enum devlink_command {
DEVLINK_CMD_PARAM_GET, /* can dump */
DEVLINK_CMD_PARAM_SET,
+ DEVLINK_CMD_PARAM_NEW,
+ DEVLINK_CMD_PARAM_DEL,
/* add new commands above here */
__DEVLINK_CMD_MAX,
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 3af08f4..89d948f 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -2828,6 +2828,28 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
return -EMSGSIZE;
}
+static void devlink_param_notify(struct devlink *devlink,
+ struct devlink_param_item *param_item,
+ enum devlink_command cmd)
+{
+ struct sk_buff *msg;
+ int err;
+
+ WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL);
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+ err = devlink_nl_param_fill(msg, devlink, param_item, cmd, 0, 0, 0);
+ if (err) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
+}
+
static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
struct netlink_callback *cb)
{
@@ -3019,6 +3041,7 @@ static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
return err;
}
+ devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_NEW);
return 0;
}
@@ -3042,6 +3065,7 @@ static int devlink_param_register_one(struct devlink *devlink,
param_item->param = param;
list_add_tail(¶m_item->list, &devlink->param_list);
+ devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_NEW);
return 0;
}
@@ -3053,6 +3077,7 @@ static void devlink_param_unregister_one(struct devlink *devlink,
param_item = devlink_param_find_by_name(&devlink->param_list,
param->name);
WARN_ON(!param_item);
+ devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_DEL);
list_del(¶m_item->list);
kfree(param_item);
}
@@ -4039,10 +4064,35 @@ int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
param_item->driverinit_value = init_val;
param_item->driverinit_value_valid = true;
+ devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_NEW);
return 0;
}
EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
+/**
+ * devlink_param_value_changed - notify devlink on a parameter's value
+ * change. Should be called by the driver
+ * right after the change.
+ *
+ * @devlink: devlink
+ * @param_id: parameter ID
+ *
+ * This function should be used by the driver to notify devlink on value
+ * change, excluding driverinit configuration mode.
+ * For driverinit configuration mode driver should use the function
+ * devlink_param_driverinit_value_set() instead.
+ */
+void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
+{
+ struct devlink_param_item *param_item;
+
+ param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
+ WARN_ON(!param_item);
+
+ devlink_param_notify(devlink, param_item, DEVLINK_CMD_PARAM_NEW);
+}
+EXPORT_SYMBOL_GPL(devlink_param_value_changed);
+
static int __init devlink_module_init(void)
{
return genl_register_family(&devlink_nl_family);
--
1.8.3.1
From: Vasundhara Volam <[email protected]>
enable_sriov - Enables Single-Root Input/Output Virtualization(SR-IOV)
characteristic of the device.
Reviewed-by: Michael Chan <[email protected]>
Signed-off-by: Vasundhara Volam <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
include/net/devlink.h | 4 ++++
net/core/devlink.c | 6 +++++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index a1c230d..8ed57138 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -358,6 +358,7 @@ struct devlink_param_item {
enum devlink_param_generic_id {
DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
+ DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
/* add new param generic ids above here*/
__DEVLINK_PARAM_GENERIC_ID_MAX,
@@ -370,6 +371,9 @@ enum devlink_param_generic_id {
#define DEVLINK_PARAM_GENERIC_MAX_MACS_NAME "max_macs"
#define DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE DEVLINK_PARAM_TYPE_U32
+#define DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME "enable_sriov"
+#define DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE DEVLINK_PARAM_TYPE_BOOL
+
#define DEVLINK_PARAM_GENERIC(_id, _cmodes, _get, _set, _validate) \
{ \
.id = DEVLINK_PARAM_GENERIC_ID_##_id, \
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 5bbd0aa..470f3db 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -2615,7 +2615,11 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
.name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
.type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
},
-
+ {
+ .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
+ .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
+ .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
+ },
};
static int devlink_param_generic_verify(const struct devlink_param *param)
--
1.8.3.1
Add mlx4_devlink_reload() to support devlink reload operation.
Add mlx4_devlink_param_load_driverinit_values() to load values which
were set using driverinit configuration mode.
Signed-off-by: Moshe Shemesh <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
drivers/net/ethernet/mellanox/mlx4/catas.c | 2 +-
drivers/net/ethernet/mellanox/mlx4/main.c | 53 +++++++++++++++++++++++++++++-
drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 +-
3 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c
index e2b6b0c..8afe4b5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/catas.c
+++ b/drivers/net/ethernet/mellanox/mlx4/catas.c
@@ -212,7 +212,7 @@ static void mlx4_handle_error_state(struct mlx4_dev_persistent *persist)
mutex_lock(&persist->interface_state_mutex);
if (persist->interface_state & MLX4_INTERFACE_STATE_UP &&
!(persist->interface_state & MLX4_INTERFACE_STATE_DELETION)) {
- err = mlx4_restart_one(persist->pdev);
+ err = mlx4_restart_one(persist->pdev, false, NULL);
mlx4_info(persist->dev, "mlx4_restart_one was ended, ret=%d\n",
err);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 2445f79..c42eddf 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -3852,8 +3852,57 @@ static int mlx4_devlink_port_type_set(struct devlink_port *devlink_port,
return __set_port_type(info, mlx4_port_type);
}
+static void mlx4_devlink_param_load_driverinit_values(struct devlink *devlink)
+{
+ union devlink_param_value saved_value;
+ int err;
+
+ err = devlink_param_driverinit_value_get(devlink,
+ DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
+ &saved_value);
+ if (!err && mlx4_internal_err_reset != saved_value.vbool) {
+ mlx4_internal_err_reset = saved_value.vbool;
+ /* Notify on value changed on runtime configuration mode */
+ devlink_param_value_changed(devlink,
+ DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET);
+ }
+ err = devlink_param_driverinit_value_get(devlink,
+ DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
+ &saved_value);
+ if (!err)
+ log_num_mac = order_base_2(saved_value.vu32);
+ err = devlink_param_driverinit_value_get(devlink,
+ MLX4_DEVLINK_PARAM_ID_ENABLE_64B_CQE_EQE,
+ &saved_value);
+ if (!err)
+ enable_64b_cqe_eqe = saved_value.vbool;
+ err = devlink_param_driverinit_value_get(devlink,
+ MLX4_DEVLINK_PARAM_ID_ENABLE_4K_UAR,
+ &saved_value);
+ if (!err)
+ enable_4k_uar = saved_value.vbool;
+}
+
+static int mlx4_devlink_reload(struct devlink *devlink,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx4_priv *priv = devlink_priv(devlink);
+ struct mlx4_dev *dev = &priv->dev;
+ struct mlx4_dev_persistent *persist = dev->persist;
+ int err;
+
+ if (persist->num_vfs)
+ mlx4_warn(persist->dev, "Reload performed on PF, will cause reset on operating Virtual Functions\n");
+ err = mlx4_restart_one(persist->pdev, true, devlink);
+ if (err)
+ mlx4_err(persist->dev, "mlx4_restart_one failed, ret=%d\n", err);
+
+ return err;
+}
+
static const struct devlink_ops mlx4_devlink_ops = {
.port_type_set = mlx4_devlink_port_type_set,
+ .reload = mlx4_devlink_reload,
};
static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -4064,7 +4113,7 @@ static int restore_current_port_types(struct mlx4_dev *dev,
return err;
}
-int mlx4_restart_one(struct pci_dev *pdev)
+int mlx4_restart_one(struct pci_dev *pdev, bool reload, struct devlink *devlink)
{
struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
struct mlx4_dev *dev = persist->dev;
@@ -4077,6 +4126,8 @@ int mlx4_restart_one(struct pci_dev *pdev)
memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs));
mlx4_unload_one(pdev);
+ if (reload)
+ mlx4_devlink_param_load_driverinit_values(devlink);
err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv, 1);
if (err) {
mlx4_err(dev, "%s: ERROR: mlx4_load_one failed, pci_name=%s, err=%d\n",
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index cb9e923..2ebaa3b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -1042,7 +1042,8 @@ int mlx4_calc_vf_counters(struct mlx4_dev *dev, int slave, int port,
void mlx4_stop_catas_poll(struct mlx4_dev *dev);
int mlx4_catas_init(struct mlx4_dev *dev);
void mlx4_catas_end(struct mlx4_dev *dev);
-int mlx4_restart_one(struct pci_dev *pdev);
+int mlx4_restart_one(struct pci_dev *pdev, bool reload,
+ struct devlink *devlink);
int mlx4_register_device(struct mlx4_dev *dev);
void mlx4_unregister_device(struct mlx4_dev *dev);
void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type,
--
1.8.3.1
Add 2 first generic parameters to devlink configuration parameters set:
internal_err_reset - When set enables reset device on internal errors.
max_macs - max number of MACs per ETH port.
Signed-off-by: Moshe Shemesh <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
include/net/devlink.h | 31 +++++++++++++++++++++++++++++++
net/core/devlink.c | 14 +++++++++++++-
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 792edaa..a1c230d 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -356,12 +356,43 @@ struct devlink_param_item {
};
enum devlink_param_generic_id {
+ DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
+ DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
/* add new param generic ids above here*/
__DEVLINK_PARAM_GENERIC_ID_MAX,
DEVLINK_PARAM_GENERIC_ID_MAX = __DEVLINK_PARAM_GENERIC_ID_MAX - 1,
};
+#define DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME "internal_error_reset"
+#define DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE DEVLINK_PARAM_TYPE_BOOL
+
+#define DEVLINK_PARAM_GENERIC_MAX_MACS_NAME "max_macs"
+#define DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE DEVLINK_PARAM_TYPE_U32
+
+#define DEVLINK_PARAM_GENERIC(_id, _cmodes, _get, _set, _validate) \
+{ \
+ .id = DEVLINK_PARAM_GENERIC_ID_##_id, \
+ .name = DEVLINK_PARAM_GENERIC_##_id##_NAME, \
+ .type = DEVLINK_PARAM_GENERIC_##_id##_TYPE, \
+ .generic = true, \
+ .supported_cmodes = _cmodes, \
+ .get = _get, \
+ .set = _set, \
+ .validate = _validate, \
+}
+
+#define DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes, _get, _set, _validate) \
+{ \
+ .id = _id, \
+ .name = _name, \
+ .type = _type, \
+ .supported_cmodes = _cmodes, \
+ .get = _get, \
+ .set = _set, \
+ .validate = _validate, \
+}
+
struct devlink_ops {
int (*reload)(struct devlink *devlink, struct netlink_ext_ack *extack);
int (*port_type_set)(struct devlink_port *devlink_port,
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 89d948f..5bbd0aa 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -2604,7 +2604,19 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
return devlink->ops->reload(devlink, info->extack);
}
-static const struct devlink_param devlink_param_generic[] = {};
+static const struct devlink_param devlink_param_generic[] = {
+ {
+ .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
+ .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
+ .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
+ },
+ {
+ .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
+ .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
+ .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
+ },
+
+};
static int devlink_param_generic_verify(const struct devlink_param *param)
{
--
1.8.3.1
Add param get command which gets data per parameter.
Option to dump the parameters data per device.
Signed-off-by: Moshe Shemesh <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
include/uapi/linux/devlink.h | 11 ++
net/core/devlink.c | 250 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 261 insertions(+)
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index d814fa6..2ccfe84 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -78,6 +78,8 @@ enum devlink_command {
*/
DEVLINK_CMD_RELOAD,
+ DEVLINK_CMD_PARAM_GET, /* can dump */
+
/* add new commands above here */
__DEVLINK_CMD_MAX,
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
@@ -248,6 +250,15 @@ enum devlink_attr {
DEVLINK_ATTR_PORT_NUMBER, /* u32 */
DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER, /* u32 */
+ DEVLINK_ATTR_PARAM, /* nested */
+ DEVLINK_ATTR_PARAM_NAME, /* string */
+ DEVLINK_ATTR_PARAM_GENERIC, /* flag */
+ DEVLINK_ATTR_PARAM_TYPE, /* u8 */
+ DEVLINK_ATTR_PARAM_VALUES_LIST, /* nested */
+ DEVLINK_ATTR_PARAM_VALUE, /* nested */
+ DEVLINK_ATTR_PARAM_VALUE_DATA, /* dynamic */
+ DEVLINK_ATTR_PARAM_VALUE_CMODE, /* u8 */
+
/* add new attributes above here, update the policy in devlink.c */
__DEVLINK_ATTR_MAX,
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 41b1a5d..b22d412 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -2645,6 +2645,248 @@ static int devlink_param_driver_verify(const struct devlink_param *param)
return NULL;
}
+static bool
+devlink_param_cmode_is_supported(const struct devlink_param *param,
+ enum devlink_param_cmode cmode)
+{
+ return test_bit(cmode, ¶m->supported_cmodes);
+}
+
+static int devlink_param_get(struct devlink *devlink,
+ const struct devlink_param *param,
+ struct devlink_param_gset_ctx *ctx)
+{
+ if (!param->get)
+ return -EOPNOTSUPP;
+ return param->get(devlink, param->id, ctx);
+}
+
+static int
+devlink_param_type_to_nla_type(enum devlink_param_type param_type)
+{
+ switch (param_type) {
+ case DEVLINK_PARAM_TYPE_U8:
+ return NLA_U8;
+ case DEVLINK_PARAM_TYPE_U16:
+ return NLA_U16;
+ case DEVLINK_PARAM_TYPE_U32:
+ return NLA_U32;
+ case DEVLINK_PARAM_TYPE_STRING:
+ return NLA_STRING;
+ case DEVLINK_PARAM_TYPE_BOOL:
+ return NLA_FLAG;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int
+devlink_nl_param_value_fill_one(struct sk_buff *msg,
+ enum devlink_param_type type,
+ enum devlink_param_cmode cmode,
+ union devlink_param_value val)
+{
+ struct nlattr *param_value_attr;
+
+ param_value_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUE);
+ if (!param_value_attr)
+ goto nla_put_failure;
+
+ if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
+ goto value_nest_cancel;
+
+ switch (type) {
+ case DEVLINK_PARAM_TYPE_U8:
+ if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
+ goto value_nest_cancel;
+ break;
+ case DEVLINK_PARAM_TYPE_U16:
+ if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
+ goto value_nest_cancel;
+ break;
+ case DEVLINK_PARAM_TYPE_U32:
+ if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
+ goto value_nest_cancel;
+ break;
+ case DEVLINK_PARAM_TYPE_STRING:
+ if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
+ val.vstr))
+ goto value_nest_cancel;
+ break;
+ case DEVLINK_PARAM_TYPE_BOOL:
+ if (val.vbool &&
+ nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
+ goto value_nest_cancel;
+ break;
+ }
+
+ nla_nest_end(msg, param_value_attr);
+ return 0;
+
+value_nest_cancel:
+ nla_nest_cancel(msg, param_value_attr);
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
+static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
+ struct devlink_param_item *param_item,
+ enum devlink_command cmd,
+ u32 portid, u32 seq, int flags)
+{
+ union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
+ const struct devlink_param *param = param_item->param;
+ struct devlink_param_gset_ctx ctx;
+ struct nlattr *param_values_list;
+ struct nlattr *param_attr;
+ int nla_type;
+ void *hdr;
+ int err;
+ int i;
+
+ /* Get value from driver part to driverinit configuration mode */
+ for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
+ if (!devlink_param_cmode_is_supported(param, i))
+ continue;
+ if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
+ if (!param_item->driverinit_value_valid)
+ return -EOPNOTSUPP;
+ param_value[i] = param_item->driverinit_value;
+ } else {
+ ctx.cmode = i;
+ err = devlink_param_get(devlink, param, &ctx);
+ if (err)
+ return err;
+ param_value[i] = ctx.val;
+ }
+ }
+
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ if (devlink_nl_put_handle(msg, devlink))
+ goto genlmsg_cancel;
+ param_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM);
+ if (!param_attr)
+ goto genlmsg_cancel;
+ if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
+ goto param_nest_cancel;
+ if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
+ goto param_nest_cancel;
+
+ nla_type = devlink_param_type_to_nla_type(param->type);
+ if (nla_type < 0)
+ goto param_nest_cancel;
+ if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
+ goto param_nest_cancel;
+
+ param_values_list = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUES_LIST);
+ if (!param_values_list)
+ goto param_nest_cancel;
+
+ for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
+ if (!devlink_param_cmode_is_supported(param, i))
+ continue;
+ err = devlink_nl_param_value_fill_one(msg, param->type,
+ i, param_value[i]);
+ if (err)
+ goto values_list_nest_cancel;
+ }
+
+ nla_nest_end(msg, param_values_list);
+ nla_nest_end(msg, param_attr);
+ genlmsg_end(msg, hdr);
+ return 0;
+
+values_list_nest_cancel:
+ nla_nest_end(msg, param_values_list);
+param_nest_cancel:
+ nla_nest_cancel(msg, param_attr);
+genlmsg_cancel:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
+ struct netlink_callback *cb)
+{
+ struct devlink_param_item *param_item;
+ struct devlink *devlink;
+ int start = cb->args[0];
+ int idx = 0;
+ int err;
+
+ mutex_lock(&devlink_mutex);
+ list_for_each_entry(devlink, &devlink_list, list) {
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
+ continue;
+ mutex_lock(&devlink->lock);
+ list_for_each_entry(param_item, &devlink->param_list, list) {
+ if (idx < start) {
+ idx++;
+ continue;
+ }
+ err = devlink_nl_param_fill(msg, devlink, param_item,
+ DEVLINK_CMD_PARAM_GET,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ NLM_F_MULTI);
+ if (err) {
+ mutex_unlock(&devlink->lock);
+ goto out;
+ }
+ idx++;
+ }
+ mutex_unlock(&devlink->lock);
+ }
+out:
+ mutex_unlock(&devlink_mutex);
+
+ cb->args[0] = idx;
+ return msg->len;
+}
+
+static struct devlink_param_item *
+devlink_param_get_from_info(struct devlink *devlink,
+ struct genl_info *info)
+{
+ char *param_name;
+
+ if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
+ return NULL;
+
+ param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
+ return devlink_param_find_by_name(&devlink->param_list, param_name);
+}
+
+static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct devlink *devlink = info->user_ptr[0];
+ struct devlink_param_item *param_item;
+ struct sk_buff *msg;
+ int err;
+
+ param_item = devlink_param_get_from_info(devlink, info);
+ if (!param_item)
+ return -EINVAL;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ err = devlink_nl_param_fill(msg, devlink, param_item,
+ DEVLINK_CMD_PARAM_GET,
+ info->snd_portid, info->snd_seq, 0);
+ if (err) {
+ nlmsg_free(msg);
+ return err;
+ }
+
+ return genlmsg_reply(msg, info);
+}
+
static int devlink_param_register_one(struct devlink *devlink,
const struct devlink_param *param)
{
@@ -2883,6 +3125,14 @@ static void devlink_param_unregister_one(struct devlink *devlink,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
DEVLINK_NL_FLAG_NO_LOCK,
},
+ {
+ .cmd = DEVLINK_CMD_PARAM_GET,
+ .doit = devlink_nl_cmd_param_get_doit,
+ .dumpit = devlink_nl_cmd_param_get_dumpit,
+ .policy = devlink_nl_policy,
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+ /* can be retrieved by unprivileged users */
+ },
};
static struct genl_family devlink_nl_family __ro_after_init = {
--
1.8.3.1
Define configuration parameters data structure.
Add functions to register and unregister the driver supported
configuration parameters table.
For each parameter registered, the driver should fill all the parameter's
fields. In case the only supported configuration mode is "driverinit"
the parameter's get()/set() functions are not required and should be set
to NULL, for any other configuration mode, these functions are required
and should be set by the driver.
Signed-off-by: Moshe Shemesh <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
include/net/devlink.h | 85 +++++++++++++++++++++++++
include/uapi/linux/devlink.h | 10 +++
net/core/devlink.c | 148 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 243 insertions(+)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index e336ea9..4a0687a 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -27,6 +27,7 @@ struct devlink {
struct list_head sb_list;
struct list_head dpipe_table_list;
struct list_head resource_list;
+ struct list_head param_list;
struct devlink_dpipe_headers *dpipe_headers;
const struct devlink_ops *ops;
struct device *dev;
@@ -295,6 +296,68 @@ struct devlink_resource {
#define DEVLINK_RESOURCE_ID_PARENT_TOP 0
+#define DEVLINK_PARAM_MAX_STRING_VALUE 32
+enum devlink_param_type {
+ DEVLINK_PARAM_TYPE_U8,
+ DEVLINK_PARAM_TYPE_U16,
+ DEVLINK_PARAM_TYPE_U32,
+ DEVLINK_PARAM_TYPE_STRING,
+ DEVLINK_PARAM_TYPE_BOOL,
+};
+
+union devlink_param_value {
+ u8 vu8;
+ u16 vu16;
+ u32 vu32;
+ const char *vstr;
+ bool vbool;
+};
+
+struct devlink_param_gset_ctx {
+ union devlink_param_value val;
+ enum devlink_param_cmode cmode;
+};
+
+/**
+ * struct devlink_param - devlink configuration parameter data
+ * @name: name of the parameter
+ * @generic: indicates if the parameter is generic or driver specific
+ * @type: parameter type
+ * @supported_cmodes: bitmap of supported configuration modes
+ * @get: get parameter value, used for runtime and permanent
+ * configuration modes
+ * @set: set parameter value, used for runtime and permanent
+ * configuration modes
+ *
+ * This struct should be used by the driver to fill the data for
+ * a parameter it registers.
+ */
+struct devlink_param {
+ u32 id;
+ const char *name;
+ bool generic;
+ enum devlink_param_type type;
+ unsigned long supported_cmodes;
+ int (*get)(struct devlink *devlink, u32 id,
+ struct devlink_param_gset_ctx *ctx);
+ int (*set)(struct devlink *devlink, u32 id,
+ struct devlink_param_gset_ctx *ctx);
+};
+
+struct devlink_param_item {
+ struct list_head list;
+ const struct devlink_param *param;
+ union devlink_param_value driverinit_value;
+ bool driverinit_value_valid;
+};
+
+enum devlink_param_generic_id {
+
+ /* add new param generic ids above here*/
+ __DEVLINK_PARAM_GENERIC_ID_MAX,
+ DEVLINK_PARAM_GENERIC_ID_MAX = __DEVLINK_PARAM_GENERIC_ID_MAX - 1,
+};
+
struct devlink_ops {
int (*reload)(struct devlink *devlink, struct netlink_ext_ack *extack);
int (*port_type_set)(struct devlink_port *devlink_port,
@@ -430,6 +493,12 @@ void devlink_resource_occ_get_register(struct devlink *devlink,
void *occ_get_priv);
void devlink_resource_occ_get_unregister(struct devlink *devlink,
u64 resource_id);
+int devlink_params_register(struct devlink *devlink,
+ const struct devlink_param *params,
+ size_t params_count);
+void devlink_params_unregister(struct devlink *devlink,
+ const struct devlink_param *params,
+ size_t params_count);
#else
@@ -622,6 +691,22 @@ static inline bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
{
}
+static inline int
+devlink_params_register(struct devlink *devlink,
+ const struct devlink_param *params,
+ size_t params_count)
+{
+ return 0;
+}
+
+static inline void
+devlink_params_unregister(struct devlink *devlink,
+ const struct devlink_param *params,
+ size_t params_count)
+{
+
+}
+
#endif
#endif /* _NET_DEVLINK_H_ */
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 75cb545..d814fa6 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -142,6 +142,16 @@ enum devlink_port_flavour {
*/
};
+enum devlink_param_cmode {
+ DEVLINK_PARAM_CMODE_RUNTIME,
+ DEVLINK_PARAM_CMODE_DRIVERINIT,
+ DEVLINK_PARAM_CMODE_PERMANENT,
+
+ /* Add new configuration modes above */
+ __DEVLINK_PARAM_CMODE_MAX,
+ DEVLINK_PARAM_CMODE_MAX = __DEVLINK_PARAM_CMODE_MAX - 1
+};
+
enum devlink_attr {
/* don't change the order or add anything between, this is ABI! */
DEVLINK_ATTR_UNSPEC,
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 2209970..41b1a5d 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -2604,6 +2604,82 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
return devlink->ops->reload(devlink, info->extack);
}
+static const struct devlink_param devlink_param_generic[] = {};
+
+static int devlink_param_generic_verify(const struct devlink_param *param)
+{
+ /* verify it match generic parameter by id and name */
+ if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
+ return -EINVAL;
+ if (strcmp(param->name, devlink_param_generic[param->id].name))
+ return -ENOENT;
+
+ WARN_ON(param->type != devlink_param_generic[param->id].type);
+
+ return 0;
+}
+
+static int devlink_param_driver_verify(const struct devlink_param *param)
+{
+ int i;
+
+ if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
+ return -EINVAL;
+ /* verify no such name in generic params */
+ for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
+ if (!strcmp(param->name, devlink_param_generic[i].name))
+ return -EEXIST;
+
+ return 0;
+}
+
+static struct devlink_param_item *
+devlink_param_find_by_name(struct list_head *param_list,
+ const char *param_name)
+{
+ struct devlink_param_item *param_item;
+
+ list_for_each_entry(param_item, param_list, list)
+ if (!strcmp(param_item->param->name, param_name))
+ return param_item;
+ return NULL;
+}
+
+static int devlink_param_register_one(struct devlink *devlink,
+ const struct devlink_param *param)
+{
+ struct devlink_param_item *param_item;
+
+ if (devlink_param_find_by_name(&devlink->param_list,
+ param->name))
+ return -EEXIST;
+
+ if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
+ WARN_ON(param->get || param->set);
+ else
+ WARN_ON(!param->get || !param->set);
+
+ param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
+ if (!param_item)
+ return -ENOMEM;
+ param_item->param = param;
+
+ list_add_tail(¶m_item->list, &devlink->param_list);
+ return 0;
+}
+
+static void devlink_param_unregister_one(struct devlink *devlink,
+ const struct devlink_param *param)
+{
+ struct devlink_param_item *param_item;
+
+ param_item = devlink_param_find_by_name(&devlink->param_list,
+ param->name);
+ WARN_ON(!param_item);
+ list_del(¶m_item->list);
+ kfree(param_item);
+}
+
static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
@@ -2845,6 +2921,7 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
INIT_LIST_HEAD(&devlink->sb_list);
INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
INIT_LIST_HEAD(&devlink->resource_list);
+ INIT_LIST_HEAD(&devlink->param_list);
mutex_init(&devlink->lock);
return devlink;
}
@@ -3434,6 +3511,77 @@ void devlink_resource_occ_get_unregister(struct devlink *devlink,
}
EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
+/**
+ * devlink_params_register - register configuration parameters
+ *
+ * @devlink: devlink
+ * @params: configuration parameters array
+ * @params_count: number of parameters provided
+ *
+ * Register the configuration parameters supported by the driver.
+ */
+int devlink_params_register(struct devlink *devlink,
+ const struct devlink_param *params,
+ size_t params_count)
+{
+ const struct devlink_param *param = params;
+ int i;
+ int err;
+
+ mutex_lock(&devlink->lock);
+ for (i = 0; i < params_count; i++, param++) {
+ if (!param || !param->name || !param->supported_cmodes) {
+ err = -EINVAL;
+ goto rollback;
+ }
+ if (param->generic) {
+ err = devlink_param_generic_verify(param);
+ if (err)
+ goto rollback;
+ } else {
+ err = devlink_param_driver_verify(param);
+ if (err)
+ goto rollback;
+ }
+ err = devlink_param_register_one(devlink, param);
+ if (err)
+ goto rollback;
+ }
+
+ mutex_unlock(&devlink->lock);
+ return 0;
+
+rollback:
+ if (!i)
+ goto unlock;
+ for (param--; i > 0; i--, param--)
+ devlink_param_unregister_one(devlink, param);
+unlock:
+ mutex_unlock(&devlink->lock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(devlink_params_register);
+
+/**
+ * devlink_params_unregister - unregister configuration parameters
+ * @devlink: devlink
+ * @params: configuration parameters to unregister
+ * @params_count: number of parameters provided
+ */
+void devlink_params_unregister(struct devlink *devlink,
+ const struct devlink_param *params,
+ size_t params_count)
+{
+ const struct devlink_param *param = params;
+ int i;
+
+ mutex_lock(&devlink->lock);
+ for (i = 0; i < params_count; i++, param++)
+ devlink_param_unregister_one(devlink, param);
+ mutex_unlock(&devlink->lock);
+}
+EXPORT_SYMBOL_GPL(devlink_params_unregister);
+
static int __init devlink_module_init(void)
{
return genl_register_family(&devlink_nl_family);
--
1.8.3.1
Add param set command to set value for a parameter.
Value can be set to any of the supported configuration modes.
Signed-off-by: Moshe Shemesh <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
include/net/devlink.h | 4 ++
include/uapi/linux/devlink.h | 1 +
net/core/devlink.c | 134 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 139 insertions(+)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 4a0687a..8806275 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -328,6 +328,7 @@ struct devlink_param_gset_ctx {
* configuration modes
* @set: set parameter value, used for runtime and permanent
* configuration modes
+ * @validate: validate input value is applicable (within value range, etc.)
*
* This struct should be used by the driver to fill the data for
* a parameter it registers.
@@ -342,6 +343,9 @@ struct devlink_param {
struct devlink_param_gset_ctx *ctx);
int (*set)(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx);
+ int (*validate)(struct devlink *devlink, u32 id,
+ union devlink_param_value val,
+ struct netlink_ext_ack *extack);
};
struct devlink_param_item {
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 2ccfe84..ea0623e 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -79,6 +79,7 @@ enum devlink_command {
DEVLINK_CMD_RELOAD,
DEVLINK_CMD_PARAM_GET, /* can dump */
+ DEVLINK_CMD_PARAM_SET,
/* add new commands above here */
__DEVLINK_CMD_MAX,
diff --git a/net/core/devlink.c b/net/core/devlink.c
index b22d412..0cd7a42 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -2661,6 +2661,15 @@ static int devlink_param_get(struct devlink *devlink,
return param->get(devlink, param->id, ctx);
}
+static int devlink_param_set(struct devlink *devlink,
+ const struct devlink_param *param,
+ struct devlink_param_gset_ctx *ctx)
+{
+ if (!param->set)
+ return -EOPNOTSUPP;
+ return param->set(devlink, param->id, ctx);
+}
+
static int
devlink_param_type_to_nla_type(enum devlink_param_type param_type)
{
@@ -2847,6 +2856,69 @@ static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
return msg->len;
}
+static int
+devlink_param_type_get_from_info(struct genl_info *info,
+ enum devlink_param_type *param_type)
+{
+ if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
+ return -EINVAL;
+
+ switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
+ case NLA_U8:
+ *param_type = DEVLINK_PARAM_TYPE_U8;
+ break;
+ case NLA_U16:
+ *param_type = DEVLINK_PARAM_TYPE_U16;
+ break;
+ case NLA_U32:
+ *param_type = DEVLINK_PARAM_TYPE_U32;
+ break;
+ case NLA_STRING:
+ *param_type = DEVLINK_PARAM_TYPE_STRING;
+ break;
+ case NLA_FLAG:
+ *param_type = DEVLINK_PARAM_TYPE_BOOL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+devlink_param_value_get_from_info(const struct devlink_param *param,
+ struct genl_info *info,
+ union devlink_param_value *value)
+{
+ if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
+ !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
+ return -EINVAL;
+
+ switch (param->type) {
+ case DEVLINK_PARAM_TYPE_U8:
+ value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
+ break;
+ case DEVLINK_PARAM_TYPE_U16:
+ value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
+ break;
+ case DEVLINK_PARAM_TYPE_U32:
+ value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
+ break;
+ case DEVLINK_PARAM_TYPE_STRING:
+ if (nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) >
+ DEVLINK_PARAM_MAX_STRING_VALUE)
+ return -EINVAL;
+ value->vstr = nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
+ break;
+ case DEVLINK_PARAM_TYPE_BOOL:
+ value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
+ true : false;
+ break;
+ }
+ return 0;
+}
+
static struct devlink_param_item *
devlink_param_get_from_info(struct devlink *devlink,
struct genl_info *info)
@@ -2887,6 +2959,58 @@ static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
return genlmsg_reply(msg, info);
}
+static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct devlink *devlink = info->user_ptr[0];
+ enum devlink_param_type param_type;
+ struct devlink_param_gset_ctx ctx;
+ enum devlink_param_cmode cmode;
+ struct devlink_param_item *param_item;
+ const struct devlink_param *param;
+ union devlink_param_value value;
+ int err = 0;
+
+ param_item = devlink_param_get_from_info(devlink, info);
+ if (!param_item)
+ return -EINVAL;
+ param = param_item->param;
+ err = devlink_param_type_get_from_info(info, ¶m_type);
+ if (err)
+ return err;
+ if (param_type != param->type)
+ return -EINVAL;
+ err = devlink_param_value_get_from_info(param, info, &value);
+ if (err)
+ return err;
+ if (param->validate) {
+ err = param->validate(devlink, param->id, value, info->extack);
+ if (err)
+ return err;
+ }
+
+ if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
+ return -EINVAL;
+ cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
+ if (!devlink_param_cmode_is_supported(param, cmode))
+ return -EOPNOTSUPP;
+
+ if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
+ param_item->driverinit_value = value;
+ param_item->driverinit_value_valid = true;
+ } else {
+ if (!param->set)
+ return -EOPNOTSUPP;
+ ctx.val = value;
+ ctx.cmode = cmode;
+ err = devlink_param_set(devlink, param, &ctx);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int devlink_param_register_one(struct devlink *devlink,
const struct devlink_param *param)
{
@@ -2942,6 +3066,9 @@ static void devlink_param_unregister_one(struct devlink *devlink,
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
[DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
[DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
+ [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
+ [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
+ [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
};
static const struct genl_ops devlink_nl_ops[] = {
@@ -3133,6 +3260,13 @@ static void devlink_param_unregister_one(struct devlink *devlink,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
/* can be retrieved by unprivileged users */
},
+ {
+ .cmd = DEVLINK_CMD_PARAM_SET,
+ .doit = devlink_nl_cmd_param_set_doit,
+ .policy = devlink_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+ },
};
static struct genl_family devlink_nl_family __ro_after_init = {
--
1.8.3.1
Add support for configuration parameters set and show.
Each parameter can be either generic or driver-specific.
The user can retrieve data on these configuration parameters by devlink
param show command and can set new value to a configuration parameter
by devlink param set command.
The configuration parameters can be set in different configuration
modes:
runtime - set while driver is running, no reset required.
driverinit - applied while driver initializes, requires restart
driver by devlink reload command.
permanent - written to device's non-volatile memory, hard reset
required to apply.
New commands added:
devlink dev param show [DEV name PARAMETER]
devlink dev param set DEV name PARAMETER value VALUE
cmode { permanent | driverinit | runtime }
Signed-off-by: Moshe Shemesh <[email protected]>
Signed-off-by: Jiri Pirko <[email protected]>
---
devlink/devlink.c | 454 +++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/devlink.h | 24 +++
man/man8/devlink-dev.8 | 57 ++++++
3 files changed, 535 insertions(+)
diff --git a/devlink/devlink.c b/devlink/devlink.c
index df2c66d..42fa716 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -35,6 +35,10 @@
#define ESWITCH_INLINE_MODE_NETWORK "network"
#define ESWITCH_INLINE_MODE_TRANSPORT "transport"
+#define PARAM_CMODE_RUNTIME_STR "runtime"
+#define PARAM_CMODE_DRIVERINIT_STR "driverinit"
+#define PARAM_CMODE_PERMANENT_STR "permanent"
+
static int g_new_line_count;
#define pr_err(args...) fprintf(stderr, ##args)
@@ -187,6 +191,9 @@ static void ifname_map_free(struct ifname_map *ifname_map)
#define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
#define DL_OPT_RESOURCE_PATH BIT(16)
#define DL_OPT_RESOURCE_SIZE BIT(17)
+#define DL_OPT_PARAM_NAME BIT(18)
+#define DL_OPT_PARAM_VALUE BIT(19)
+#define DL_OPT_PARAM_CMODE BIT(20)
struct dl_opts {
uint32_t present; /* flags of present items */
@@ -211,6 +218,9 @@ struct dl_opts {
uint32_t resource_size;
uint32_t resource_id;
bool resource_id_valid;
+ const char *param_name;
+ const char *param_value;
+ enum devlink_param_cmode cmode;
};
struct dl {
@@ -348,6 +358,12 @@ static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
[DEVLINK_ATTR_DPIPE_FIELD_ID] = MNL_TYPE_U32,
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = MNL_TYPE_U32,
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_PARAM] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_PARAM_NAME] = MNL_TYPE_STRING,
+ [DEVLINK_ATTR_PARAM_TYPE] = MNL_TYPE_U8,
+ [DEVLINK_ATTR_PARAM_VALUES_LIST] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_PARAM_VALUE] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_PARAM_VALUE_CMODE] = MNL_TYPE_U8,
};
static int attr_cb(const struct nlattr *attr, void *data)
@@ -514,6 +530,34 @@ static int strtouint16_t(const char *str, uint16_t *p_val)
return 0;
}
+static int strtouint8_t(const char *str, uint8_t *p_val)
+{
+ char *endptr;
+ unsigned long int val;
+
+ val = strtoul(str, &endptr, 10);
+ if (endptr == str || *endptr != '\0')
+ return -EINVAL;
+ if (val > UCHAR_MAX)
+ return -ERANGE;
+ *p_val = val;
+ return 0;
+}
+
+static int strtobool(const char *str, bool *p_val)
+{
+ bool val;
+
+ if (!strcmp(str, "true") || !strcmp(str, "1"))
+ val = true;
+ else if (!strcmp(str, "false") || !strcmp(str, "0"))
+ val = false;
+ else
+ return -EINVAL;
+ *p_val = val;
+ return 0;
+}
+
static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
{
strslashrsplit(str, p_bus_name, p_dev_name);
@@ -792,6 +836,22 @@ static int eswitch_encap_mode_get(const char *typestr, bool *p_mode)
return 0;
}
+static int param_cmode_get(const char *cmodestr,
+ enum devlink_param_cmode *cmode)
+{
+ if (strcmp(cmodestr, PARAM_CMODE_RUNTIME_STR) == 0) {
+ *cmode = DEVLINK_PARAM_CMODE_RUNTIME;
+ } else if (strcmp(cmodestr, PARAM_CMODE_DRIVERINIT_STR) == 0) {
+ *cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
+ } else if (strcmp(cmodestr, PARAM_CMODE_PERMANENT_STR) == 0) {
+ *cmode = DEVLINK_PARAM_CMODE_PERMANENT;
+ } else {
+ pr_err("Unknown configuration mode \"%s\"\n", cmodestr);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int dl_argv_parse(struct dl *dl, uint32_t o_required,
uint32_t o_optional)
{
@@ -973,6 +1033,32 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
if (err)
return err;
o_found |= DL_OPT_RESOURCE_SIZE;
+ } else if (dl_argv_match(dl, "name") &&
+ (o_all & DL_OPT_PARAM_NAME)) {
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &opts->param_name);
+ if (err)
+ return err;
+ o_found |= DL_OPT_PARAM_NAME;
+ } else if (dl_argv_match(dl, "value") &&
+ (o_all & DL_OPT_PARAM_VALUE)) {
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &opts->param_value);
+ if (err)
+ return err;
+ o_found |= DL_OPT_PARAM_VALUE;
+ } else if (dl_argv_match(dl, "cmode") &&
+ (o_all & DL_OPT_PARAM_CMODE)) {
+ const char *cmodestr;
+
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &cmodestr);
+ if (err)
+ return err;
+ err = param_cmode_get(cmodestr, &opts->cmode);
+ if (err)
+ return err;
+ o_found |= DL_OPT_PARAM_CMODE;
} else {
pr_err("Unknown option \"%s\"\n", dl_argv(dl));
return -EINVAL;
@@ -1057,6 +1143,24 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
return -EINVAL;
}
+ if ((o_required & DL_OPT_PARAM_NAME) &&
+ !(o_found & DL_OPT_PARAM_NAME)) {
+ pr_err("Parameter name expected.\n");
+ return -EINVAL;
+ }
+
+ if ((o_required & DL_OPT_PARAM_VALUE) &&
+ !(o_found & DL_OPT_PARAM_VALUE)) {
+ pr_err("Value to set expected.\n");
+ return -EINVAL;
+ }
+
+ if ((o_required & DL_OPT_PARAM_CMODE) &&
+ !(o_found & DL_OPT_PARAM_CMODE)) {
+ pr_err("Configuration mode expected.\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -1121,6 +1225,12 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
if (opts->present & DL_OPT_RESOURCE_SIZE)
mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_SIZE,
opts->resource_size);
+ if (opts->present & DL_OPT_PARAM_NAME)
+ mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME,
+ opts->param_name);
+ if (opts->present & DL_OPT_PARAM_CMODE)
+ mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE,
+ opts->cmode);
}
static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
@@ -1179,6 +1289,8 @@ static void cmd_dev_help(void)
pr_err(" [ inline-mode { none | link | network | transport } ]\n");
pr_err(" [ encap { disable | enable } ]\n");
pr_err(" devlink dev eswitch show DEV\n");
+ pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
+ pr_err(" devlink dev param show [DEV name PARAMETER]\n");
pr_err(" devlink dev reload DEV\n");
}
@@ -1393,6 +1505,14 @@ static void pr_out_str(struct dl *dl, const char *name, const char *val)
}
}
+static void pr_out_bool(struct dl *dl, const char *name, bool val)
+{
+ if (val)
+ pr_out_str(dl, name, "true");
+ else
+ pr_out_str(dl, name, "false");
+}
+
static void pr_out_uint(struct dl *dl, const char *name, unsigned int val)
{
if (dl->json_output) {
@@ -1475,6 +1595,19 @@ static void pr_out_entry_end(struct dl *dl)
__pr_out_newline();
}
+static const char *param_cmode_name(uint8_t cmode)
+{
+ switch (cmode) {
+ case DEVLINK_PARAM_CMODE_RUNTIME:
+ return PARAM_CMODE_RUNTIME_STR;
+ case DEVLINK_PARAM_CMODE_DRIVERINIT:
+ return PARAM_CMODE_DRIVERINIT_STR;
+ case DEVLINK_PARAM_CMODE_PERMANENT:
+ return PARAM_CMODE_PERMANENT_STR;
+ default: return "<unknown type>";
+ }
+}
+
static const char *eswitch_mode_name(uint32_t mode)
{
switch (mode) {
@@ -1593,6 +1726,304 @@ static int cmd_dev_eswitch(struct dl *dl)
return -ENOENT;
}
+static void pr_out_param_value(struct dl *dl, int nla_type, struct nlattr *nl)
+{
+ struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
+ struct nlattr *val_attr;
+ int err;
+
+ err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
+ if (err != MNL_CB_OK)
+ return;
+
+ if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
+ (nla_type != MNL_TYPE_FLAG &&
+ !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
+ return;
+
+ pr_out_str(dl, "cmode",
+ param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
+ val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
+
+ switch (nla_type) {
+ case MNL_TYPE_U8:
+ pr_out_uint(dl, "value", mnl_attr_get_u8(val_attr));
+ break;
+ case MNL_TYPE_U16:
+ pr_out_uint(dl, "value", mnl_attr_get_u16(val_attr));
+ break;
+ case MNL_TYPE_U32:
+ pr_out_uint(dl, "value", mnl_attr_get_u32(val_attr));
+ break;
+ case MNL_TYPE_STRING:
+ pr_out_str(dl, "value", mnl_attr_get_str(val_attr));
+ break;
+ case MNL_TYPE_FLAG:
+ pr_out_bool(dl, "value", val_attr ? true : false);
+ break;
+ }
+}
+
+static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
+{
+ struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
+ struct nlattr *param_value_attr;
+ int nla_type;
+ int err;
+
+ err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
+ if (err != MNL_CB_OK)
+ return;
+ if (!nla_param[DEVLINK_ATTR_PARAM_NAME] ||
+ !nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
+ !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
+ return;
+
+ if (array)
+ pr_out_handle_start_arr(dl, tb);
+ else
+ __pr_out_handle_start(dl, tb, true, false);
+
+ nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
+
+ pr_out_str(dl, "name",
+ mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]));
+
+ if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
+ pr_out_str(dl, "type", "driver-specific");
+ else
+ pr_out_str(dl, "type", "generic");
+
+ pr_out_array_start(dl, "values");
+ mnl_attr_for_each_nested(param_value_attr,
+ nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
+ pr_out_entry_start(dl);
+ pr_out_param_value(dl, nla_type, param_value_attr);
+ pr_out_entry_end(dl);
+ }
+ pr_out_array_end(dl);
+ pr_out_handle_end(dl);
+}
+
+static int cmd_dev_param_show_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+ struct dl *dl = data;
+
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+ !tb[DEVLINK_ATTR_PARAM])
+ return MNL_CB_ERROR;
+ pr_out_param(dl, tb, true);
+ return MNL_CB_OK;
+}
+
+struct param_ctx {
+ struct dl *dl;
+ int nla_type;
+ union {
+ uint8_t vu8;
+ uint16_t vu16;
+ uint32_t vu32;
+ const char *vstr;
+ bool vbool;
+ } value;
+};
+
+static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+ struct nlattr *param_value_attr;
+ enum devlink_param_cmode cmode;
+ struct param_ctx *ctx = data;
+ struct dl *dl = ctx->dl;
+ int nla_type;
+ int err;
+
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+ !tb[DEVLINK_ATTR_PARAM])
+ return MNL_CB_ERROR;
+
+ err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
+ if (err != MNL_CB_OK)
+ return MNL_CB_ERROR;
+
+ if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
+ !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
+ return MNL_CB_ERROR;
+
+ nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
+ mnl_attr_for_each_nested(param_value_attr,
+ nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
+ struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
+ struct nlattr *val_attr;
+
+ err = mnl_attr_parse_nested(param_value_attr,
+ attr_cb, nla_value);
+ if (err != MNL_CB_OK)
+ return MNL_CB_ERROR;
+
+ if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
+ (nla_type != MNL_TYPE_FLAG &&
+ !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
+ return MNL_CB_ERROR;
+
+ cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
+ if (cmode == dl->opts.cmode) {
+ val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
+ switch (nla_type) {
+ case MNL_TYPE_U8:
+ ctx->value.vu8 = mnl_attr_get_u8(val_attr);
+ break;
+ case MNL_TYPE_U16:
+ ctx->value.vu16 = mnl_attr_get_u16(val_attr);
+ break;
+ case MNL_TYPE_U32:
+ ctx->value.vu32 = mnl_attr_get_u32(val_attr);
+ break;
+ case MNL_TYPE_STRING:
+ ctx->value.vstr = mnl_attr_get_str(val_attr);
+ break;
+ case MNL_TYPE_FLAG:
+ ctx->value.vbool = val_attr ? true : false;
+ break;
+ }
+ break;
+ }
+ }
+ ctx->nla_type = nla_type;
+ return MNL_CB_OK;
+}
+
+static int cmd_dev_param_set(struct dl *dl)
+{
+ struct param_ctx ctx = {};
+ struct nlmsghdr *nlh;
+ uint32_t val_u32;
+ uint16_t val_u16;
+ uint8_t val_u8;
+ bool val_bool;
+ int err;
+
+ err = dl_argv_parse(dl, DL_OPT_HANDLE |
+ DL_OPT_PARAM_NAME |
+ DL_OPT_PARAM_VALUE |
+ DL_OPT_PARAM_CMODE, 0);
+ if (err)
+ return err;
+
+ /* Get value type */
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET,
+ NLM_F_REQUEST | NLM_F_ACK);
+ dl_opts_put(nlh, dl);
+
+ ctx.dl = dl;
+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
+ if (err)
+ return err;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_SET,
+ NLM_F_REQUEST | NLM_F_ACK);
+ dl_opts_put(nlh, dl);
+
+ mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
+ switch (ctx.nla_type) {
+ case MNL_TYPE_U8:
+ err = strtouint8_t(dl->opts.param_value, &val_u8);
+ if (err)
+ goto err_param_value_parse;
+ if (val_u8 == ctx.value.vu8)
+ return 0;
+ mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
+ break;
+ case MNL_TYPE_U16:
+ err = strtouint16_t(dl->opts.param_value, &val_u16);
+ if (err)
+ goto err_param_value_parse;
+ if (val_u16 == ctx.value.vu16)
+ return 0;
+ mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
+ break;
+ case MNL_TYPE_U32:
+ err = strtouint32_t(dl->opts.param_value, &val_u32);
+ if (err)
+ goto err_param_value_parse;
+ if (val_u32 == ctx.value.vu32)
+ return 0;
+ mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
+ break;
+ case MNL_TYPE_FLAG:
+ err = strtobool(dl->opts.param_value, &val_bool);
+ if (err)
+ goto err_param_value_parse;
+ if (val_bool == ctx.value.vbool)
+ return 0;
+ if (val_bool)
+ mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
+ 0, NULL);
+ break;
+ case MNL_TYPE_STRING:
+ mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
+ dl->opts.param_value);
+ if (!strcmp(dl->opts.param_value, ctx.value.vstr))
+ return 0;
+ break;
+ default:
+ printf("Value type not supported\n");
+ return -ENOTSUP;
+ }
+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+
+err_param_value_parse:
+ pr_err("Value \"%s\" is not a number or not within range\n",
+ dl->opts.param_value);
+ return err;
+}
+
+static int cmd_dev_param_show(struct dl *dl)
+{
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+ struct nlmsghdr *nlh;
+ int err;
+
+ if (dl_argc(dl) == 0)
+ flags |= NLM_F_DUMP;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET, flags);
+
+ if (dl_argc(dl) > 0) {
+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE |
+ DL_OPT_PARAM_NAME, 0);
+ if (err)
+ return err;
+ }
+
+ pr_out_section_start(dl, "param");
+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_show_cb, dl);
+ pr_out_section_end(dl);
+ return err;
+}
+
+static int cmd_dev_param(struct dl *dl)
+{
+ if (dl_argv_match(dl, "help")) {
+ cmd_dev_help();
+ return 0;
+ } else if (dl_argv_match(dl, "show") ||
+ dl_argv_match(dl, "list") || dl_no_arg(dl)) {
+ dl_arg_inc(dl);
+ return cmd_dev_param_show(dl);
+ } else if (dl_argv_match(dl, "set")) {
+ dl_arg_inc(dl);
+ return cmd_dev_param_set(dl);
+ }
+ pr_err("Command \"%s\" not found\n", dl_argv(dl));
+ return -ENOENT;
+}
static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
{
struct dl *dl = data;
@@ -1669,6 +2100,9 @@ static int cmd_dev(struct dl *dl)
} else if (dl_argv_match(dl, "reload")) {
dl_arg_inc(dl);
return cmd_dev_reload(dl);
+ } else if (dl_argv_match(dl, "param")) {
+ dl_arg_inc(dl);
+ return cmd_dev_param(dl);
}
pr_err("Command \"%s\" not found\n", dl_argv(dl));
return -ENOENT;
@@ -2632,6 +3066,10 @@ static const char *cmd_name(uint8_t cmd)
case DEVLINK_CMD_PORT_SET: return "set";
case DEVLINK_CMD_PORT_NEW: return "new";
case DEVLINK_CMD_PORT_DEL: return "del";
+ case DEVLINK_CMD_PARAM_GET: return "get";
+ case DEVLINK_CMD_PARAM_SET: return "set";
+ case DEVLINK_CMD_PARAM_NEW: return "new";
+ case DEVLINK_CMD_PARAM_DEL: return "del";
default: return "<unknown cmd>";
}
}
@@ -2650,6 +3088,11 @@ static const char *cmd_obj(uint8_t cmd)
case DEVLINK_CMD_PORT_NEW:
case DEVLINK_CMD_PORT_DEL:
return "port";
+ case DEVLINK_CMD_PARAM_GET:
+ case DEVLINK_CMD_PARAM_SET:
+ case DEVLINK_CMD_PARAM_NEW:
+ case DEVLINK_CMD_PARAM_DEL:
+ return "param";
default: return "<unknown obj>";
}
}
@@ -2706,6 +3149,17 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
pr_out_mon_header(genl->cmd);
pr_out_port(dl, tb);
break;
+ case DEVLINK_CMD_PARAM_GET: /* fall through */
+ case DEVLINK_CMD_PARAM_SET: /* fall through */
+ case DEVLINK_CMD_PARAM_NEW: /* fall through */
+ case DEVLINK_CMD_PARAM_DEL:
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+ !tb[DEVLINK_ATTR_PARAM])
+ return MNL_CB_ERROR;
+ pr_out_mon_header(genl->cmd);
+ pr_out_param(dl, tb, false);
+ break;
}
return MNL_CB_OK;
}
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 493f71f..f7fadd7 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -78,6 +78,11 @@ enum devlink_command {
*/
DEVLINK_CMD_RELOAD,
+ DEVLINK_CMD_PARAM_GET, /* can dump */
+ DEVLINK_CMD_PARAM_SET,
+ DEVLINK_CMD_PARAM_NEW,
+ DEVLINK_CMD_PARAM_DEL,
+
/* add new commands above here */
__DEVLINK_CMD_MAX,
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
@@ -142,6 +147,16 @@ enum devlink_port_flavour {
*/
};
+enum devlink_param_cmode {
+ DEVLINK_PARAM_CMODE_RUNTIME,
+ DEVLINK_PARAM_CMODE_DRIVERINIT,
+ DEVLINK_PARAM_CMODE_PERMANENT,
+
+ /* Add new configuration modes above */
+ __DEVLINK_PARAM_CMODE_MAX,
+ DEVLINK_PARAM_CMODE_MAX = __DEVLINK_PARAM_CMODE_MAX - 1
+};
+
enum devlink_attr {
/* don't change the order or add anything between, this is ABI! */
DEVLINK_ATTR_UNSPEC,
@@ -238,6 +253,15 @@ enum devlink_attr {
DEVLINK_ATTR_PORT_NUMBER, /* u32 */
DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER, /* u32 */
+ DEVLINK_ATTR_PARAM, /* nested */
+ DEVLINK_ATTR_PARAM_NAME, /* string */
+ DEVLINK_ATTR_PARAM_GENERIC, /* flag */
+ DEVLINK_ATTR_PARAM_TYPE, /* u8 */
+ DEVLINK_ATTR_PARAM_VALUES_LIST, /* nested */
+ DEVLINK_ATTR_PARAM_VALUE, /* nested */
+ DEVLINK_ATTR_PARAM_VALUE_DATA, /* dynamic */
+ DEVLINK_ATTR_PARAM_VALUE_CMODE, /* u8 */
+
/* add new attributes above here, update the policy in devlink.c */
__DEVLINK_ATTR_MAX,
diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8
index 7c749dd..d985da1 100644
--- a/man/man8/devlink-dev.8
+++ b/man/man8/devlink-dev.8
@@ -43,6 +43,23 @@ devlink-dev \- devlink device configuration
.IR DEV
.ti -8
+.BR "devlink dev param set"
+.IR DEV
+.BR name
+.IR PARAMETER
+.BR value
+.IR VALUE
+.BR cmode " { " runtime " | " driverinit " | " permanent " } "
+
+.ti -8
+.BR "devlink dev param show"
+.RI "[ "
+.IR DEV
+.BR name
+.IR PARAMETER
+.RI "]"
+
+.ti -8
.BR "devlink dev reload"
.IR DEV
@@ -98,6 +115,36 @@ Set eswitch encapsulation support
.I enable
- Enable encapsulation support
+.SS devlink dev param set - set new value to devlink device configuration parameter
+
+.TP
+.BI name " PARAMETER"
+Specify parameter name to set.
+
+.TP
+.BI value " VALUE"
+New value to set.
+
+.TP
+.BR cmode " { " runtime " | " driverinit " | " permanent " } "
+Configuration mode in which the new value is set.
+
+.I runtime
+- Set new value while driver is running. This configuration mode doesn't require any reset to apply the new value.
+
+.I driverinit
+- Set new value which will be applied during driver initialization. This configuration mode requires restart driver by devlink reload command to apply the new value.
+
+.I permanent
+- New value is written to device's non-volatile memory. This configuration mode requires hard reset to apply the new value.
+
+.SS devlink dev param show - display devlink device supported configuration parameters attributes
+
+.BR name
+.IR PARAMETER
+Specify parameter name to show.
+If this argument is omitted all parameters supported by devlink devices are listed.
+
.SS devlink dev reload - perform hot reload of the driver.
.PP
@@ -126,6 +173,16 @@ devlink dev eswitch set pci/0000:01:00.0 mode switchdev
Sets the eswitch mode of specified devlink device to switchdev.
.RE
.PP
+devlink dev param show pci/0000:01:00.0 name max_macs
+.RS 4
+Shows the parameter max_macs attributes.
+.RE
+.PP
+devlink dev param set pci/0000:01:00.0 name internal_error_reset value true cmode runtime
+.RS 4
+Sets the parameter internal_error_reset of specified devlink device to true.
+.RE
+.PP
devlink dev reload pci/0000:01:00.0
.RS 4
Performs hot reload of specified devlink device.
--
1.8.3.1
From: Moshe Shemesh <[email protected]>
Date: Wed, 4 Jul 2018 14:30:27 +0300
> Add configuration parameters setting through devlink.
> Each device registers supported configuration parameters table.
> Each parameter can be either generic or driver specific.
> The user can retrieve data on these parameters by "devlink param show"
> command and can set new value to a parameter by "devlink param set"
> command.
> The parameters can be set in different configuration modes:
> runtime - set while driver is running, no reset required.
> driverinit - applied while driver initializes, requires restart
> driver by devlink reload command.
> permanent - written to device's non-volatile memory, hard reset required.
>
> The patches at the end of the patchset introduce few params that are using
> the introduced infrastructure on mlx4 and bnxt.
>
> Command examples and output:
...
Looks great, series applied, thanks!