Commit 04007961 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

ethtool: netlink: convert commands to common SET



Convert all SET commands where new common code is applicable.

Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 99132b6e
Loading
Loading
Loading
Loading
+36 −56
Original line number Diff line number Diff line
@@ -86,18 +86,6 @@ static int channels_fill_reply(struct sk_buff *skb,
	return 0;
}

const struct ethnl_request_ops ethnl_channels_request_ops = {
	.request_cmd		= ETHTOOL_MSG_CHANNELS_GET,
	.reply_cmd		= ETHTOOL_MSG_CHANNELS_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_CHANNELS_HEADER,
	.req_info_size		= sizeof(struct channels_req_info),
	.reply_data_size	= sizeof(struct channels_reply_data),

	.prepare_data		= channels_prepare_data,
	.reply_size		= channels_reply_size,
	.fill_reply		= channels_fill_reply,
};

/* CHANNELS_SET */

const struct nla_policy ethnl_channels_set_policy[] = {
@@ -109,36 +97,28 @@ const struct nla_policy ethnl_channels_set_policy[] = {
	[ETHTOOL_A_CHANNELS_COMBINED_COUNT]	= { .type = NLA_U32 },
};

int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
static int
ethnl_set_channels_validate(struct ethnl_req_info *req_info,
			    struct genl_info *info)
{
	const struct ethtool_ops *ops = req_info->dev->ethtool_ops;

	return ops->get_channels && ops->set_channels ? 1 : -EOPNOTSUPP;
}

static int
ethnl_set_channels(struct ethnl_req_info *req_info, struct genl_info *info)
{
	unsigned int from_channel, old_total, i;
	bool mod = false, mod_combined = false;
	struct net_device *dev = req_info->dev;
	struct ethtool_channels channels = {};
	struct ethnl_req_info req_info = {};
	struct nlattr **tb = info->attrs;
	u32 err_attr, max_rxfh_in_use;
	const struct ethtool_ops *ops;
	struct net_device *dev;
	u64 max_rxnfc_in_use;
	int ret;

	ret = ethnl_parse_header_dev_get(&req_info,
					 tb[ETHTOOL_A_CHANNELS_HEADER],
					 genl_info_net(info), info->extack,
					 true);
	if (ret < 0)
		return ret;
	dev = req_info.dev;
	ops = dev->ethtool_ops;
	ret = -EOPNOTSUPP;
	if (!ops->get_channels || !ops->set_channels)
		goto out_dev;

	rtnl_lock();
	ret = ethnl_ops_begin(dev);
	if (ret < 0)
		goto out_rtnl;
	ops->get_channels(dev, &channels);
	dev->ethtool_ops->get_channels(dev, &channels);
	old_total = channels.combined_count +
		    max(channels.rx_count, channels.tx_count);

@@ -151,9 +131,8 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
	ethnl_update_u32(&channels.combined_count,
			 tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT], &mod_combined);
	mod |= mod_combined;
	ret = 0;
	if (!mod)
		goto out_ops;
		return 0;

	/* ensure new channel counts are within limits */
	if (channels.rx_count > channels.max_rx)
@@ -167,10 +146,9 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
	else
		err_attr = 0;
	if (err_attr) {
		ret = -EINVAL;
		NL_SET_ERR_MSG_ATTR(info->extack, tb[err_attr],
				    "requested channel count exceeds maximum");
		goto out_ops;
		return -EINVAL;
	}

	/* ensure there is at least one RX and one TX channel */
@@ -183,10 +161,9 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
	if (err_attr) {
		if (mod_combined)
			err_attr = ETHTOOL_A_CHANNELS_COMBINED_COUNT;
		ret = -EINVAL;
		NL_SET_ERR_MSG_ATTR(info->extack, tb[err_attr],
				    "requested channel counts would result in no RX or TX channel being configured");
		goto out_ops;
		return -EINVAL;
	}

	/* ensure the new Rx count fits within the configured Rx flow
@@ -198,14 +175,12 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
	    ethtool_get_max_rxfh_channel(dev, &max_rxfh_in_use))
		max_rxfh_in_use = 0;
	if (channels.combined_count + channels.rx_count <= max_rxfh_in_use) {
		ret = -EINVAL;
		GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing indirection table settings");
		goto out_ops;
		return -EINVAL;
	}
	if (channels.combined_count + channels.rx_count <= max_rxnfc_in_use) {
		ret = -EINVAL;
		GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing ntuple filter settings");
		goto out_ops;
		return -EINVAL;
	}

	/* Disabling channels, query zero-copy AF_XDP sockets */
@@ -213,21 +188,26 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
		       min(channels.rx_count, channels.tx_count);
	for (i = from_channel; i < old_total; i++)
		if (xsk_get_pool_from_qid(dev, i)) {
			ret = -EINVAL;
			GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing zerocopy AF_XDP sockets");
			goto out_ops;
			return -EINVAL;
		}

	ret = dev->ethtool_ops->set_channels(dev, &channels);
	if (ret < 0)
		goto out_ops;
	ethtool_notify(dev, ETHTOOL_MSG_CHANNELS_NTF, NULL);

out_ops:
	ethnl_ops_complete(dev);
out_rtnl:
	rtnl_unlock();
out_dev:
	ethnl_parse_header_dev_put(&req_info);
	return ret;
	return ret < 0 ? ret : 1;
}

const struct ethnl_request_ops ethnl_channels_request_ops = {
	.request_cmd		= ETHTOOL_MSG_CHANNELS_GET,
	.reply_cmd		= ETHTOOL_MSG_CHANNELS_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_CHANNELS_HEADER,
	.req_info_size		= sizeof(struct channels_req_info),
	.reply_data_size	= sizeof(struct channels_reply_data),

	.prepare_data		= channels_prepare_data,
	.reply_size		= channels_reply_size,
	.fill_reply		= channels_fill_reply,

	.set_validate		= ethnl_set_channels_validate,
	.set			= ethnl_set_channels,
	.set_ntf_cmd		= ETHTOOL_MSG_CHANNELS_NTF,
};
+40 −52
Original line number Diff line number Diff line
@@ -195,18 +195,6 @@ static int coalesce_fill_reply(struct sk_buff *skb,
	return 0;
}

const struct ethnl_request_ops ethnl_coalesce_request_ops = {
	.request_cmd		= ETHTOOL_MSG_COALESCE_GET,
	.reply_cmd		= ETHTOOL_MSG_COALESCE_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_COALESCE_HEADER,
	.req_info_size		= sizeof(struct coalesce_req_info),
	.reply_data_size	= sizeof(struct coalesce_reply_data),

	.prepare_data		= coalesce_prepare_data,
	.reply_size		= coalesce_reply_size,
	.fill_reply		= coalesce_fill_reply,
};

/* COALESCE_SET */

const struct nla_policy ethnl_coalesce_set_policy[] = {
@@ -241,49 +229,44 @@ const struct nla_policy ethnl_coalesce_set_policy[] = {
	[ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS] = { .type = NLA_U32 },
};

int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info)
static int
ethnl_set_coalesce_validate(struct ethnl_req_info *req_info,
			    struct genl_info *info)
{
	struct kernel_ethtool_coalesce kernel_coalesce = {};
	struct ethtool_coalesce coalesce = {};
	struct ethnl_req_info req_info = {};
	const struct ethtool_ops *ops = req_info->dev->ethtool_ops;
	struct nlattr **tb = info->attrs;
	const struct ethtool_ops *ops;
	struct net_device *dev;
	u32 supported_params;
	bool mod = false;
	int ret;
	u16 a;

	ret = ethnl_parse_header_dev_get(&req_info,
					 tb[ETHTOOL_A_COALESCE_HEADER],
					 genl_info_net(info), info->extack,
					 true);
	if (ret < 0)
		return ret;
	dev = req_info.dev;
	ops = dev->ethtool_ops;
	ret = -EOPNOTSUPP;
	if (!ops->get_coalesce || !ops->set_coalesce)
		goto out_dev;
		return -EOPNOTSUPP;

	/* make sure that only supported parameters are present */
	supported_params = ops->supported_coalesce_params;
	for (a = ETHTOOL_A_COALESCE_RX_USECS; a < __ETHTOOL_A_COALESCE_CNT; a++)
		if (tb[a] && !(supported_params & attr_to_mask(a))) {
			ret = -EINVAL;
			NL_SET_ERR_MSG_ATTR(info->extack, tb[a],
					    "cannot modify an unsupported parameter");
			goto out_dev;
			return -EINVAL;
		}

	rtnl_lock();
	ret = ethnl_ops_begin(dev);
	if (ret < 0)
		goto out_rtnl;
	ret = ops->get_coalesce(dev, &coalesce, &kernel_coalesce,
	return 1;
}

static int
ethnl_set_coalesce(struct ethnl_req_info *req_info, struct genl_info *info)
{
	struct kernel_ethtool_coalesce kernel_coalesce = {};
	struct net_device *dev = req_info->dev;
	struct ethtool_coalesce coalesce = {};
	struct nlattr **tb = info->attrs;
	bool mod = false;
	int ret;

	ret = dev->ethtool_ops->get_coalesce(dev, &coalesce, &kernel_coalesce,
					     info->extack);
	if (ret < 0)
		goto out_ops;
		return ret;

	ethnl_update_u32(&coalesce.rx_coalesce_usecs,
			 tb[ETHTOOL_A_COALESCE_RX_USECS], &mod);
@@ -339,21 +322,26 @@ int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info)
			 tb[ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES], &mod);
	ethnl_update_u32(&kernel_coalesce.tx_aggr_time_usecs,
			 tb[ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS], &mod);
	ret = 0;
	if (!mod)
		goto out_ops;
		return 0;

	ret = dev->ethtool_ops->set_coalesce(dev, &coalesce, &kernel_coalesce,
					     info->extack);
	if (ret < 0)
		goto out_ops;
	ethtool_notify(dev, ETHTOOL_MSG_COALESCE_NTF, NULL);

out_ops:
	ethnl_ops_complete(dev);
out_rtnl:
	rtnl_unlock();
out_dev:
	ethnl_parse_header_dev_put(&req_info);
	return ret;
	return ret < 0 ? ret : 1;
}

const struct ethnl_request_ops ethnl_coalesce_request_ops = {
	.request_cmd		= ETHTOOL_MSG_COALESCE_GET,
	.reply_cmd		= ETHTOOL_MSG_COALESCE_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_COALESCE_HEADER,
	.req_info_size		= sizeof(struct coalesce_req_info),
	.reply_data_size	= sizeof(struct coalesce_reply_data),

	.prepare_data		= coalesce_prepare_data,
	.reply_size		= coalesce_reply_size,
	.fill_reply		= coalesce_fill_reply,

	.set_validate		= ethnl_set_coalesce_validate,
	.set			= ethnl_set_coalesce,
	.set_ntf_cmd		= ETHTOOL_MSG_COALESCE_NTF,
};
+30 −41
Original line number Diff line number Diff line
@@ -63,18 +63,6 @@ static int debug_fill_reply(struct sk_buff *skb,
				  netif_msg_class_names, compact);
}

const struct ethnl_request_ops ethnl_debug_request_ops = {
	.request_cmd		= ETHTOOL_MSG_DEBUG_GET,
	.reply_cmd		= ETHTOOL_MSG_DEBUG_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_DEBUG_HEADER,
	.req_info_size		= sizeof(struct debug_req_info),
	.reply_data_size	= sizeof(struct debug_reply_data),

	.prepare_data		= debug_prepare_data,
	.reply_size		= debug_reply_size,
	.fill_reply		= debug_fill_reply,
};

/* DEBUG_SET */

const struct nla_policy ethnl_debug_set_policy[] = {
@@ -83,46 +71,47 @@ const struct nla_policy ethnl_debug_set_policy[] = {
	[ETHTOOL_A_DEBUG_MSGMASK]	= { .type = NLA_NESTED },
};

int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info)
static int
ethnl_set_debug_validate(struct ethnl_req_info *req_info,
			 struct genl_info *info)
{
	const struct ethtool_ops *ops = req_info->dev->ethtool_ops;

	return ops->get_msglevel && ops->set_msglevel ? 1 : -EOPNOTSUPP;
}

static int
ethnl_set_debug(struct ethnl_req_info *req_info, struct genl_info *info)
{
	struct ethnl_req_info req_info = {};
	struct net_device *dev = req_info->dev;
	struct nlattr **tb = info->attrs;
	struct net_device *dev;
	bool mod = false;
	u32 msg_mask;
	int ret;

	ret = ethnl_parse_header_dev_get(&req_info,
					 tb[ETHTOOL_A_DEBUG_HEADER],
					 genl_info_net(info), info->extack,
					 true);
	if (ret < 0)
		return ret;
	dev = req_info.dev;
	ret = -EOPNOTSUPP;
	if (!dev->ethtool_ops->get_msglevel || !dev->ethtool_ops->set_msglevel)
		goto out_dev;

	rtnl_lock();
	ret = ethnl_ops_begin(dev);
	if (ret < 0)
		goto out_rtnl;

	msg_mask = dev->ethtool_ops->get_msglevel(dev);
	ret = ethnl_update_bitset32(&msg_mask, NETIF_MSG_CLASS_COUNT,
				    tb[ETHTOOL_A_DEBUG_MSGMASK],
				    netif_msg_class_names, info->extack, &mod);
	if (ret < 0 || !mod)
		goto out_ops;
		return ret;

	dev->ethtool_ops->set_msglevel(dev, msg_mask);
	ethtool_notify(dev, ETHTOOL_MSG_DEBUG_NTF, NULL);

out_ops:
	ethnl_ops_complete(dev);
out_rtnl:
	rtnl_unlock();
out_dev:
	ethnl_parse_header_dev_put(&req_info);
	return ret;
	return 1;
}

const struct ethnl_request_ops ethnl_debug_request_ops = {
	.request_cmd		= ETHTOOL_MSG_DEBUG_GET,
	.reply_cmd		= ETHTOOL_MSG_DEBUG_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_DEBUG_HEADER,
	.req_info_size		= sizeof(struct debug_req_info),
	.reply_data_size	= sizeof(struct debug_reply_data),

	.prepare_data		= debug_prepare_data,
	.reply_size		= debug_reply_size,
	.fill_reply		= debug_fill_reply,

	.set_validate		= ethnl_set_debug_validate,
	.set			= ethnl_set_debug,
	.set_ntf_cmd		= ETHTOOL_MSG_DEBUG_NTF,
};
+31 −47
Original line number Diff line number Diff line
@@ -108,18 +108,6 @@ static int eee_fill_reply(struct sk_buff *skb,
	return 0;
}

const struct ethnl_request_ops ethnl_eee_request_ops = {
	.request_cmd		= ETHTOOL_MSG_EEE_GET,
	.reply_cmd		= ETHTOOL_MSG_EEE_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_EEE_HEADER,
	.req_info_size		= sizeof(struct eee_req_info),
	.reply_data_size	= sizeof(struct eee_reply_data),

	.prepare_data		= eee_prepare_data,
	.reply_size		= eee_reply_size,
	.fill_reply		= eee_fill_reply,
};

/* EEE_SET */

const struct nla_policy ethnl_eee_set_policy[] = {
@@ -131,60 +119,56 @@ const struct nla_policy ethnl_eee_set_policy[] = {
	[ETHTOOL_A_EEE_TX_LPI_TIMER]	= { .type = NLA_U32 },
};

int ethnl_set_eee(struct sk_buff *skb, struct genl_info *info)
static int
ethnl_set_eee_validate(struct ethnl_req_info *req_info, struct genl_info *info)
{
	const struct ethtool_ops *ops = req_info->dev->ethtool_ops;

	return ops->get_eee && ops->set_eee ? 1 : -EOPNOTSUPP;
}

static int
ethnl_set_eee(struct ethnl_req_info *req_info, struct genl_info *info)
{
	struct ethnl_req_info req_info = {};
	struct net_device *dev = req_info->dev;
	struct nlattr **tb = info->attrs;
	const struct ethtool_ops *ops;
	struct ethtool_eee eee = {};
	struct net_device *dev;
	bool mod = false;
	int ret;

	ret = ethnl_parse_header_dev_get(&req_info,
					 tb[ETHTOOL_A_EEE_HEADER],
					 genl_info_net(info), info->extack,
					 true);
	ret = dev->ethtool_ops->get_eee(dev, &eee);
	if (ret < 0)
		return ret;
	dev = req_info.dev;
	ops = dev->ethtool_ops;
	ret = -EOPNOTSUPP;
	if (!ops->get_eee || !ops->set_eee)
		goto out_dev;

	rtnl_lock();
	ret = ethnl_ops_begin(dev);
	if (ret < 0)
		goto out_rtnl;
	ret = ops->get_eee(dev, &eee);
	if (ret < 0)
		goto out_ops;

	ret = ethnl_update_bitset32(&eee.advertised, EEE_MODES_COUNT,
				    tb[ETHTOOL_A_EEE_MODES_OURS],
				    link_mode_names, info->extack, &mod);
	if (ret < 0)
		goto out_ops;
		return ret;
	ethnl_update_bool32(&eee.eee_enabled, tb[ETHTOOL_A_EEE_ENABLED], &mod);
	ethnl_update_bool32(&eee.tx_lpi_enabled,
			    tb[ETHTOOL_A_EEE_TX_LPI_ENABLED], &mod);
	ethnl_update_u32(&eee.tx_lpi_timer, tb[ETHTOOL_A_EEE_TX_LPI_TIMER],
			 &mod);
	ret = 0;
	if (!mod)
		goto out_ops;
		return 0;

	ret = dev->ethtool_ops->set_eee(dev, &eee);
	if (ret < 0)
		goto out_ops;
	ethtool_notify(dev, ETHTOOL_MSG_EEE_NTF, NULL);

out_ops:
	ethnl_ops_complete(dev);
out_rtnl:
	rtnl_unlock();
out_dev:
	ethnl_parse_header_dev_put(&req_info);
	return ret;
	return ret < 0 ? ret : 1;
}

const struct ethnl_request_ops ethnl_eee_request_ops = {
	.request_cmd		= ETHTOOL_MSG_EEE_GET,
	.reply_cmd		= ETHTOOL_MSG_EEE_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_EEE_HEADER,
	.req_info_size		= sizeof(struct eee_req_info),
	.reply_data_size	= sizeof(struct eee_reply_data),

	.prepare_data		= eee_prepare_data,
	.reply_size		= eee_reply_size,
	.fill_reply		= eee_fill_reply,

	.set_validate		= ethnl_set_eee_validate,
	.set			= ethnl_set_eee,
	.set_ntf_cmd		= ETHTOOL_MSG_EEE_NTF,
};
+33 −50
Original line number Diff line number Diff line
@@ -217,18 +217,6 @@ static int fec_fill_reply(struct sk_buff *skb,
	return 0;
}

const struct ethnl_request_ops ethnl_fec_request_ops = {
	.request_cmd		= ETHTOOL_MSG_FEC_GET,
	.reply_cmd		= ETHTOOL_MSG_FEC_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_FEC_HEADER,
	.req_info_size		= sizeof(struct fec_req_info),
	.reply_data_size	= sizeof(struct fec_reply_data),

	.prepare_data		= fec_prepare_data,
	.reply_size		= fec_reply_size,
	.fill_reply		= fec_fill_reply,
};

/* FEC_SET */

const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_AUTO + 1] = {
@@ -237,36 +225,28 @@ const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_AUTO + 1] = {
	[ETHTOOL_A_FEC_AUTO]	= NLA_POLICY_MAX(NLA_U8, 1),
};

int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info)
static int
ethnl_set_fec_validate(struct ethnl_req_info *req_info, struct genl_info *info)
{
	const struct ethtool_ops *ops = req_info->dev->ethtool_ops;

	return ops->get_fecparam && ops->set_fecparam ? 1 : -EOPNOTSUPP;
}

static int
ethnl_set_fec(struct ethnl_req_info *req_info, struct genl_info *info)
{
	__ETHTOOL_DECLARE_LINK_MODE_MASK(fec_link_modes) = {};
	struct ethnl_req_info req_info = {};
	struct net_device *dev = req_info->dev;
	struct nlattr **tb = info->attrs;
	struct ethtool_fecparam fec = {};
	const struct ethtool_ops *ops;
	struct net_device *dev;
	bool mod = false;
	u8 fec_auto;
	int ret;

	ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_FEC_HEADER],
					 genl_info_net(info), info->extack,
					 true);
	ret = dev->ethtool_ops->get_fecparam(dev, &fec);
	if (ret < 0)
		return ret;
	dev = req_info.dev;
	ops = dev->ethtool_ops;
	ret = -EOPNOTSUPP;
	if (!ops->get_fecparam || !ops->set_fecparam)
		goto out_dev;

	rtnl_lock();
	ret = ethnl_ops_begin(dev);
	if (ret < 0)
		goto out_rtnl;
	ret = ops->get_fecparam(dev, &fec);
	if (ret < 0)
		goto out_ops;

	ethtool_fec_to_link_modes(fec.fec, fec_link_modes, &fec_auto);

@@ -275,36 +255,39 @@ int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info)
				  tb[ETHTOOL_A_FEC_MODES],
				  link_mode_names, info->extack, &mod);
	if (ret < 0)
		goto out_ops;
		return ret;
	ethnl_update_u8(&fec_auto, tb[ETHTOOL_A_FEC_AUTO], &mod);

	ret = 0;
	if (!mod)
		goto out_ops;
		return 0;

	ret = ethtool_link_modes_to_fecparam(&fec, fec_link_modes, fec_auto);
	if (ret) {
		NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_FEC_MODES],
				    "invalid FEC modes requested");
		goto out_ops;
		return ret;
	}
	if (!fec.fec) {
		ret = -EINVAL;
		NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_FEC_MODES],
				    "no FEC modes set");
		goto out_ops;
		return -EINVAL;
	}

	ret = dev->ethtool_ops->set_fecparam(dev, &fec);
	if (ret < 0)
		goto out_ops;
	ethtool_notify(dev, ETHTOOL_MSG_FEC_NTF, NULL);

out_ops:
	ethnl_ops_complete(dev);
out_rtnl:
	rtnl_unlock();
out_dev:
	ethnl_parse_header_dev_put(&req_info);
	return ret;
	return ret < 0 ? ret : 1;
}

const struct ethnl_request_ops ethnl_fec_request_ops = {
	.request_cmd		= ETHTOOL_MSG_FEC_GET,
	.reply_cmd		= ETHTOOL_MSG_FEC_GET_REPLY,
	.hdr_attr		= ETHTOOL_A_FEC_HEADER,
	.req_info_size		= sizeof(struct fec_req_info),
	.reply_data_size	= sizeof(struct fec_reply_data),

	.prepare_data		= fec_prepare_data,
	.reply_size		= fec_reply_size,
	.fill_reply		= fec_fill_reply,

	.set_validate		= ethnl_set_fec_validate,
	.set			= ethnl_set_fec,
	.set_ntf_cmd		= ETHTOOL_MSG_FEC_NTF,
};
Loading