devlink: Add devlink_param register and unregister

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 <moshe@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Moshe Shemesh 2018-07-04 14:30:28 +03:00 committed by David S. Miller
parent 827ad90cfa
commit eabaef1896
3 changed files with 243 additions and 0 deletions

View File

@ -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 @@ devlink_resource_occ_get_unregister(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_ */

View File

@ -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,

View File

@ -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(&param_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(&param_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 @@ out:
}
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);