xref: /openbmc/linux/net/ethtool/pause.c (revision 7f59fb32)
17f59fb32SMichal Kubecek // SPDX-License-Identifier: GPL-2.0-only
27f59fb32SMichal Kubecek 
37f59fb32SMichal Kubecek #include "netlink.h"
47f59fb32SMichal Kubecek #include "common.h"
57f59fb32SMichal Kubecek 
67f59fb32SMichal Kubecek struct pause_req_info {
77f59fb32SMichal Kubecek 	struct ethnl_req_info		base;
87f59fb32SMichal Kubecek };
97f59fb32SMichal Kubecek 
107f59fb32SMichal Kubecek struct pause_reply_data {
117f59fb32SMichal Kubecek 	struct ethnl_reply_data		base;
127f59fb32SMichal Kubecek 	struct ethtool_pauseparam	pauseparam;
137f59fb32SMichal Kubecek };
147f59fb32SMichal Kubecek 
157f59fb32SMichal Kubecek #define PAUSE_REPDATA(__reply_base) \
167f59fb32SMichal Kubecek 	container_of(__reply_base, struct pause_reply_data, base)
177f59fb32SMichal Kubecek 
187f59fb32SMichal Kubecek static const struct nla_policy
197f59fb32SMichal Kubecek pause_get_policy[ETHTOOL_A_PAUSE_MAX + 1] = {
207f59fb32SMichal Kubecek 	[ETHTOOL_A_PAUSE_UNSPEC]		= { .type = NLA_REJECT },
217f59fb32SMichal Kubecek 	[ETHTOOL_A_PAUSE_HEADER]		= { .type = NLA_NESTED },
227f59fb32SMichal Kubecek 	[ETHTOOL_A_PAUSE_AUTONEG]		= { .type = NLA_REJECT },
237f59fb32SMichal Kubecek 	[ETHTOOL_A_PAUSE_RX]			= { .type = NLA_REJECT },
247f59fb32SMichal Kubecek 	[ETHTOOL_A_PAUSE_TX]			= { .type = NLA_REJECT },
257f59fb32SMichal Kubecek };
267f59fb32SMichal Kubecek 
277f59fb32SMichal Kubecek static int pause_prepare_data(const struct ethnl_req_info *req_base,
287f59fb32SMichal Kubecek 			      struct ethnl_reply_data *reply_base,
297f59fb32SMichal Kubecek 			      struct genl_info *info)
307f59fb32SMichal Kubecek {
317f59fb32SMichal Kubecek 	struct pause_reply_data *data = PAUSE_REPDATA(reply_base);
327f59fb32SMichal Kubecek 	struct net_device *dev = reply_base->dev;
337f59fb32SMichal Kubecek 	int ret;
347f59fb32SMichal Kubecek 
357f59fb32SMichal Kubecek 	if (!dev->ethtool_ops->get_pauseparam)
367f59fb32SMichal Kubecek 		return -EOPNOTSUPP;
377f59fb32SMichal Kubecek 	ret = ethnl_ops_begin(dev);
387f59fb32SMichal Kubecek 	if (ret < 0)
397f59fb32SMichal Kubecek 		return ret;
407f59fb32SMichal Kubecek 	dev->ethtool_ops->get_pauseparam(dev, &data->pauseparam);
417f59fb32SMichal Kubecek 	ethnl_ops_complete(dev);
427f59fb32SMichal Kubecek 
437f59fb32SMichal Kubecek 	return 0;
447f59fb32SMichal Kubecek }
457f59fb32SMichal Kubecek 
467f59fb32SMichal Kubecek static int pause_reply_size(const struct ethnl_req_info *req_base,
477f59fb32SMichal Kubecek 			    const struct ethnl_reply_data *reply_base)
487f59fb32SMichal Kubecek {
497f59fb32SMichal Kubecek 	return nla_total_size(sizeof(u8)) +	/* _PAUSE_AUTONEG */
507f59fb32SMichal Kubecek 		nla_total_size(sizeof(u8)) +	/* _PAUSE_RX */
517f59fb32SMichal Kubecek 		nla_total_size(sizeof(u8));	/* _PAUSE_TX */
527f59fb32SMichal Kubecek }
537f59fb32SMichal Kubecek 
547f59fb32SMichal Kubecek static int pause_fill_reply(struct sk_buff *skb,
557f59fb32SMichal Kubecek 			    const struct ethnl_req_info *req_base,
567f59fb32SMichal Kubecek 			    const struct ethnl_reply_data *reply_base)
577f59fb32SMichal Kubecek {
587f59fb32SMichal Kubecek 	const struct pause_reply_data *data = PAUSE_REPDATA(reply_base);
597f59fb32SMichal Kubecek 	const struct ethtool_pauseparam *pauseparam = &data->pauseparam;
607f59fb32SMichal Kubecek 
617f59fb32SMichal Kubecek 	if (nla_put_u8(skb, ETHTOOL_A_PAUSE_AUTONEG, !!pauseparam->autoneg) ||
627f59fb32SMichal Kubecek 	    nla_put_u8(skb, ETHTOOL_A_PAUSE_RX, !!pauseparam->rx_pause) ||
637f59fb32SMichal Kubecek 	    nla_put_u8(skb, ETHTOOL_A_PAUSE_TX, !!pauseparam->tx_pause))
647f59fb32SMichal Kubecek 		return -EMSGSIZE;
657f59fb32SMichal Kubecek 
667f59fb32SMichal Kubecek 	return 0;
677f59fb32SMichal Kubecek }
687f59fb32SMichal Kubecek 
697f59fb32SMichal Kubecek const struct ethnl_request_ops ethnl_pause_request_ops = {
707f59fb32SMichal Kubecek 	.request_cmd		= ETHTOOL_MSG_PAUSE_GET,
717f59fb32SMichal Kubecek 	.reply_cmd		= ETHTOOL_MSG_PAUSE_GET_REPLY,
727f59fb32SMichal Kubecek 	.hdr_attr		= ETHTOOL_A_PAUSE_HEADER,
737f59fb32SMichal Kubecek 	.max_attr		= ETHTOOL_A_PAUSE_MAX,
747f59fb32SMichal Kubecek 	.req_info_size		= sizeof(struct pause_req_info),
757f59fb32SMichal Kubecek 	.reply_data_size	= sizeof(struct pause_reply_data),
767f59fb32SMichal Kubecek 	.request_policy		= pause_get_policy,
777f59fb32SMichal Kubecek 
787f59fb32SMichal Kubecek 	.prepare_data		= pause_prepare_data,
797f59fb32SMichal Kubecek 	.reply_size		= pause_reply_size,
807f59fb32SMichal Kubecek 	.fill_reply		= pause_fill_reply,
817f59fb32SMichal Kubecek };
82