864 lines · 22.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Copyright (c) 2016 Mellanox Technologies. All rights reserved. * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> */ #include "devl_internal.h" 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,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,		.name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,		.type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,		.name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,		.type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,		.name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,		.type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,		.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,		.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,		.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,		.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,		.name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,		.type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,		.name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,		.type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,		.name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,		.type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET,		.name = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_NAME,		.type = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH,		.name = DEVLINK_PARAM_GENERIC_ENABLE_ETH_NAME,		.type = DEVLINK_PARAM_GENERIC_ENABLE_ETH_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,		.name = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_NAME,		.type = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET,		.name = DEVLINK_PARAM_GENERIC_ENABLE_VNET_NAME,		.type = DEVLINK_PARAM_GENERIC_ENABLE_VNET_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_IWARP,		.name = DEVLINK_PARAM_GENERIC_ENABLE_IWARP_NAME,		.type = DEVLINK_PARAM_GENERIC_ENABLE_IWARP_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_IO_EQ_SIZE,		.name = DEVLINK_PARAM_GENERIC_IO_EQ_SIZE_NAME,		.type = DEVLINK_PARAM_GENERIC_IO_EQ_SIZE_TYPE,	},	{		.id = DEVLINK_PARAM_GENERIC_ID_EVENT_EQ_SIZE,		.name = DEVLINK_PARAM_GENERIC_EVENT_EQ_SIZE_NAME,		.type = DEVLINK_PARAM_GENERIC_EVENT_EQ_SIZE_TYPE,	},}; 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 xarray *params, const char *param_name){	struct devlink_param_item *param_item;	unsigned long param_id; 	xa_for_each(params, param_id, param_item) {		if (!strcmp(param_item->param->name, param_name))			return param_item;	}	return NULL;} static struct devlink_param_item *devlink_param_find_by_id(struct xarray *params, u32 param_id){	return xa_load(params, param_id);} static booldevlink_param_cmode_is_supported(const struct devlink_param *param,				 enum devlink_param_cmode cmode){	return test_bit(cmode, &param->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_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 intdevlink_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 intdevlink_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_noflag(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,				 unsigned int port_index,				 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];	bool param_value_set[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_new_valid)				param_value[i] = param_item->driverinit_value_new;			else if (param_item->driverinit_value_valid)				param_value[i] = param_item->driverinit_value;			else				return -EOPNOTSUPP;		} else {			ctx.cmode = i;			err = devlink_param_get(devlink, param, &ctx);			if (err)				return err;			param_value[i] = ctx.val;		}		param_value_set[i] = true;	} 	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; 	if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||	    cmd == DEVLINK_CMD_PORT_PARAM_NEW ||	    cmd == DEVLINK_CMD_PORT_PARAM_DEL)		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))			goto genlmsg_cancel; 	param_attr = nla_nest_start_noflag(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_noflag(msg,						  DEVLINK_ATTR_PARAM_VALUES_LIST);	if (!param_values_list)		goto param_nest_cancel; 	for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {		if (!param_value_set[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 void devlink_param_notify(struct devlink *devlink,				 unsigned int port_index,				 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 &&		cmd != DEVLINK_CMD_PORT_PARAM_NEW &&		cmd != DEVLINK_CMD_PORT_PARAM_DEL); 	/* devlink_notify_register() / devlink_notify_unregister()	 * will replay the notifications if the params are added/removed	 * outside of the lifetime of the instance.	 */	if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))		return; 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);	if (!msg)		return;	err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,				    0, 0, 0);	if (err) {		nlmsg_free(msg);		return;	} 	devlink_nl_notify_send(devlink, msg);} static void devlink_params_notify(struct devlink *devlink,				  enum devlink_command cmd){	struct devlink_param_item *param_item;	unsigned long param_id; 	xa_for_each(&devlink->params, param_id, param_item)		devlink_param_notify(devlink, 0, param_item, cmd);} void devlink_params_notify_register(struct devlink *devlink){	devlink_params_notify(devlink, DEVLINK_CMD_PARAM_NEW);} void devlink_params_notify_unregister(struct devlink *devlink){	devlink_params_notify(devlink, DEVLINK_CMD_PARAM_DEL);} static int devlink_nl_param_get_dump_one(struct sk_buff *msg,					 struct devlink *devlink,					 struct netlink_callback *cb,					 int flags){	struct devlink_nl_dump_state *state = devlink_dump_state(cb);	struct devlink_param_item *param_item;	unsigned long param_id;	int err = 0; 	xa_for_each_start(&devlink->params, param_id, param_item, state->idx) {		err = devlink_nl_param_fill(msg, devlink, 0, param_item,					    DEVLINK_CMD_PARAM_GET,					    NETLINK_CB(cb->skb).portid,					    cb->nlh->nlmsg_seq, flags);		if (err == -EOPNOTSUPP) {			err = 0;		} else if (err) {			state->idx = param_id;			break;		}	} 	return err;} int devlink_nl_param_get_dumpit(struct sk_buff *skb,				struct netlink_callback *cb){	return devlink_nl_dumpit(skb, cb, devlink_nl_param_get_dump_one);} static intdevlink_param_type_get_from_info(struct genl_info *info,				 enum devlink_param_type *param_type){	if (GENL_REQ_ATTR_CHECK(info, 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 intdevlink_param_value_get_from_info(const struct devlink_param *param,				  struct genl_info *info,				  union devlink_param_value *value){	struct nlattr *param_data;	int len; 	param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]; 	if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)		return -EINVAL; 	switch (param->type) {	case DEVLINK_PARAM_TYPE_U8:		if (nla_len(param_data) != sizeof(u8))			return -EINVAL;		value->vu8 = nla_get_u8(param_data);		break;	case DEVLINK_PARAM_TYPE_U16:		if (nla_len(param_data) != sizeof(u16))			return -EINVAL;		value->vu16 = nla_get_u16(param_data);		break;	case DEVLINK_PARAM_TYPE_U32:		if (nla_len(param_data) != sizeof(u32))			return -EINVAL;		value->vu32 = nla_get_u32(param_data);		break;	case DEVLINK_PARAM_TYPE_STRING:		len = strnlen(nla_data(param_data), nla_len(param_data));		if (len == nla_len(param_data) ||		    len >= __DEVLINK_PARAM_MAX_STRING_VALUE)			return -EINVAL;		strcpy(value->vstr, nla_data(param_data));		break;	case DEVLINK_PARAM_TYPE_BOOL:		if (param_data && nla_len(param_data))			return -EINVAL;		value->vbool = nla_get_flag(param_data);		break;	}	return 0;} static struct devlink_param_item *devlink_param_get_from_info(struct xarray *params, struct genl_info *info){	char *param_name; 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_NAME))		return NULL; 	param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);	return devlink_param_find_by_name(params, param_name);} 

Lines 1–500 of 864.