1444 lines · 37.8 KB · C
RawDownload
		cmd != DEVLINK_CMD_FLASH_UPDATE_END &&		cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS); 	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_flash_update_fill(msg, devlink, cmd, params);	if (err)		goto out_free_msg; 	devlink_nl_notify_send(devlink, msg);	return; out_free_msg:	nlmsg_free(msg);} static void devlink_flash_update_begin_notify(struct devlink *devlink){	struct devlink_flash_notify params = {}; 	__devlink_flash_update_notify(devlink,				      DEVLINK_CMD_FLASH_UPDATE,				      &params);} static void devlink_flash_update_end_notify(struct devlink *devlink){	struct devlink_flash_notify params = {}; 	__devlink_flash_update_notify(devlink,				      DEVLINK_CMD_FLASH_UPDATE_END,				      &params);} void devlink_flash_update_status_notify(struct devlink *devlink,					const char *status_msg,					const char *component,					unsigned long done,					unsigned long total){	struct devlink_flash_notify params = {		.status_msg = status_msg,		.component = component,		.done = done,		.total = total,	}; 	__devlink_flash_update_notify(devlink,				      DEVLINK_CMD_FLASH_UPDATE_STATUS,				      &params);}EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify); void devlink_flash_update_timeout_notify(struct devlink *devlink,					 const char *status_msg,					 const char *component,					 unsigned long timeout){	struct devlink_flash_notify params = {		.status_msg = status_msg,		.component = component,		.timeout = timeout,	}; 	__devlink_flash_update_notify(devlink,				      DEVLINK_CMD_FLASH_UPDATE_STATUS,				      &params);}EXPORT_SYMBOL_GPL(devlink_flash_update_timeout_notify); struct devlink_flash_component_lookup_ctx {	const char *lookup_name;	bool lookup_name_found;}; static voiddevlink_flash_component_lookup_cb(const char *version_name,				  enum devlink_info_version_type version_type,				  void *version_cb_priv){	struct devlink_flash_component_lookup_ctx *lookup_ctx = version_cb_priv; 	if (version_type != DEVLINK_INFO_VERSION_TYPE_COMPONENT ||	    lookup_ctx->lookup_name_found)		return; 	lookup_ctx->lookup_name_found =		!strcmp(lookup_ctx->lookup_name, version_name);} static int devlink_flash_component_get(struct devlink *devlink,				       struct nlattr *nla_component,				       const char **p_component,				       struct netlink_ext_ack *extack){	struct devlink_flash_component_lookup_ctx lookup_ctx = {};	struct devlink_info_req req = {};	const char *component;	int ret; 	if (!nla_component)		return 0; 	component = nla_data(nla_component); 	if (!devlink->ops->info_get) {		NL_SET_ERR_MSG_ATTR(extack, nla_component,				    "component update is not supported by this device");		return -EOPNOTSUPP;	} 	lookup_ctx.lookup_name = component;	req.version_cb = devlink_flash_component_lookup_cb;	req.version_cb_priv = &lookup_ctx; 	ret = devlink->ops->info_get(devlink, &req, NULL);	if (ret)		return ret; 	if (!lookup_ctx.lookup_name_found) {		NL_SET_ERR_MSG_ATTR(extack, nla_component,				    "selected component is not supported by this device");		return -EINVAL;	}	*p_component = component;	return 0;} int devlink_nl_flash_update_doit(struct sk_buff *skb, struct genl_info *info){	struct nlattr *nla_overwrite_mask, *nla_file_name;	struct devlink_flash_update_params params = {};	struct devlink *devlink = info->user_ptr[0];	const char *file_name;	u32 supported_params;	int ret; 	if (!devlink->ops->flash_update)		return -EOPNOTSUPP; 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME))		return -EINVAL; 	ret = devlink_flash_component_get(devlink,					  info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT],					  &params.component, info->extack);	if (ret)		return ret; 	supported_params = devlink->ops->supported_flash_update_params; 	nla_overwrite_mask = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK];	if (nla_overwrite_mask) {		struct nla_bitfield32 sections; 		if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK)) {			NL_SET_ERR_MSG_ATTR(info->extack, nla_overwrite_mask,					    "overwrite settings are not supported by this device");			return -EOPNOTSUPP;		}		sections = nla_get_bitfield32(nla_overwrite_mask);		params.overwrite_mask = sections.value & sections.selector;	} 	nla_file_name = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME];	file_name = nla_data(nla_file_name);	ret = request_firmware(&params.fw, file_name, devlink->dev);	if (ret) {		NL_SET_ERR_MSG_ATTR(info->extack, nla_file_name,				    "failed to locate the requested firmware file");		return ret;	} 	devlink_flash_update_begin_notify(devlink);	ret = devlink->ops->flash_update(devlink, &params, info->extack);	devlink_flash_update_end_notify(devlink); 	release_firmware(params.fw); 	return ret;} static void __devlink_compat_running_version(struct devlink *devlink,					     char *buf, size_t len){	struct devlink_info_req req = {};	const struct nlattr *nlattr;	struct sk_buff *msg;	int rem, err; 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);	if (!msg)		return; 	req.msg = msg;	err = devlink->ops->info_get(devlink, &req, NULL);	if (err)		goto free_msg; 	nla_for_each_attr_type(nlattr, DEVLINK_ATTR_INFO_VERSION_RUNNING,			       (void *)msg->data, msg->len, rem) {		const struct nlattr *kv;		int rem_kv; 		nla_for_each_nested_type(kv, DEVLINK_ATTR_INFO_VERSION_VALUE,					 nlattr, rem_kv) {			strlcat(buf, nla_data(kv), len);			strlcat(buf, " ", len);		}	}free_msg:	nlmsg_consume(msg);} void devlink_compat_running_version(struct devlink *devlink,				    char *buf, size_t len){	if (!devlink->ops->info_get)		return; 	devl_lock(devlink);	if (devl_is_registered(devlink))		__devlink_compat_running_version(devlink, buf, len);	devl_unlock(devlink);} int devlink_compat_flash_update(struct devlink *devlink, const char *file_name){	struct devlink_flash_update_params params = {};	int ret; 	devl_lock(devlink);	if (!devl_is_registered(devlink)) {		ret = -ENODEV;		goto out_unlock;	} 	if (!devlink->ops->flash_update) {		ret = -EOPNOTSUPP;		goto out_unlock;	} 	ret = request_firmware(&params.fw, file_name, devlink->dev);	if (ret)		goto out_unlock; 	devlink_flash_update_begin_notify(devlink);	ret = devlink->ops->flash_update(devlink, &params, NULL);	devlink_flash_update_end_notify(devlink); 	release_firmware(params.fw);out_unlock:	devl_unlock(devlink); 	return ret;} static intdevlink_nl_selftests_fill(struct sk_buff *msg, struct devlink *devlink,			  u32 portid, u32 seq, int flags,			  struct netlink_ext_ack *extack){	struct nlattr *selftests;	void *hdr;	int err;	int i; 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags,			  DEVLINK_CMD_SELFTESTS_GET);	if (!hdr)		return -EMSGSIZE; 	err = -EMSGSIZE;	if (devlink_nl_put_handle(msg, devlink))		goto err_cancel_msg; 	selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS);	if (!selftests)		goto err_cancel_msg; 	for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1;	     i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) {		if (devlink->ops->selftest_check(devlink, i, extack)) {			err = nla_put_flag(msg, i);			if (err)				goto err_cancel_msg;		}	} 	nla_nest_end(msg, selftests);	genlmsg_end(msg, hdr);	return 0; err_cancel_msg:	genlmsg_cancel(msg, hdr);	return err;} int devlink_nl_selftests_get_doit(struct sk_buff *skb, struct genl_info *info){	struct devlink *devlink = info->user_ptr[0];	struct sk_buff *msg;	int err; 	if (!devlink->ops->selftest_check)		return -EOPNOTSUPP; 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);	if (!msg)		return -ENOMEM; 	err = devlink_nl_selftests_fill(msg, devlink, info->snd_portid,					info->snd_seq, 0, info->extack);	if (err) {		nlmsg_free(msg);		return err;	} 	return genlmsg_reply(msg, info);} static int devlink_nl_selftests_get_dump_one(struct sk_buff *msg,					     struct devlink *devlink,					     struct netlink_callback *cb,					     int flags){	if (!devlink->ops->selftest_check)		return 0; 	return devlink_nl_selftests_fill(msg, devlink,					 NETLINK_CB(cb->skb).portid,					 cb->nlh->nlmsg_seq, flags,					 cb->extack);} int devlink_nl_selftests_get_dumpit(struct sk_buff *skb,				    struct netlink_callback *cb){	return devlink_nl_dumpit(skb, cb, devlink_nl_selftests_get_dump_one);} static int devlink_selftest_result_put(struct sk_buff *skb, unsigned int id,				       enum devlink_selftest_status test_status){	struct nlattr *result_attr; 	result_attr = nla_nest_start(skb, DEVLINK_ATTR_SELFTEST_RESULT);	if (!result_attr)		return -EMSGSIZE; 	if (nla_put_u32(skb, DEVLINK_ATTR_SELFTEST_RESULT_ID, id) ||	    nla_put_u8(skb, DEVLINK_ATTR_SELFTEST_RESULT_STATUS,		       test_status))		goto nla_put_failure; 	nla_nest_end(skb, result_attr);	return 0; nla_put_failure:	nla_nest_cancel(skb, result_attr);	return -EMSGSIZE;} static const struct nla_policy devlink_selftest_nl_policy[DEVLINK_ATTR_SELFTEST_ID_MAX + 1] = {	[DEVLINK_ATTR_SELFTEST_ID_FLASH] = { .type = NLA_FLAG },}; int devlink_nl_selftests_run_doit(struct sk_buff *skb, struct genl_info *info){	struct nlattr *tb[DEVLINK_ATTR_SELFTEST_ID_MAX + 1];	struct devlink *devlink = info->user_ptr[0];	struct nlattr *attrs, *selftests;	struct sk_buff *msg;	void *hdr;	int err;	int i; 	if (!devlink->ops->selftest_run || !devlink->ops->selftest_check)		return -EOPNOTSUPP; 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SELFTESTS))		return -EINVAL; 	attrs = info->attrs[DEVLINK_ATTR_SELFTESTS]; 	err = nla_parse_nested(tb, DEVLINK_ATTR_SELFTEST_ID_MAX, attrs,			       devlink_selftest_nl_policy, info->extack);	if (err < 0)		return err; 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);	if (!msg)		return -ENOMEM; 	err = -EMSGSIZE;	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,			  &devlink_nl_family, 0, DEVLINK_CMD_SELFTESTS_RUN);	if (!hdr)		goto free_msg; 	if (devlink_nl_put_handle(msg, devlink))		goto genlmsg_cancel; 	selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS);	if (!selftests)		goto genlmsg_cancel; 	for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1;	     i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) {		enum devlink_selftest_status test_status; 		if (nla_get_flag(tb[i])) {			if (!devlink->ops->selftest_check(devlink, i,							  info->extack)) {				if (devlink_selftest_result_put(msg, i,								DEVLINK_SELFTEST_STATUS_SKIP))					goto selftests_nest_cancel;				continue;			} 			test_status = devlink->ops->selftest_run(devlink, i,								 info->extack);			if (devlink_selftest_result_put(msg, i, test_status))				goto selftests_nest_cancel;		}	} 	nla_nest_end(msg, selftests);	genlmsg_end(msg, hdr);	return genlmsg_reply(msg, info); selftests_nest_cancel:	nla_nest_cancel(msg, selftests);genlmsg_cancel:	genlmsg_cancel(msg, hdr);free_msg:	nlmsg_free(msg);	return err;}

Lines 1001–1444 of 1444. Previous lines