xref: /openbmc/linux/net/ethtool/debug.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
16a94b8ccSMichal Kubecek // SPDX-License-Identifier: GPL-2.0-only
26a94b8ccSMichal Kubecek 
36a94b8ccSMichal Kubecek #include "netlink.h"
46a94b8ccSMichal Kubecek #include "common.h"
56a94b8ccSMichal Kubecek #include "bitset.h"
66a94b8ccSMichal Kubecek 
76a94b8ccSMichal Kubecek struct debug_req_info {
86a94b8ccSMichal Kubecek 	struct ethnl_req_info		base;
96a94b8ccSMichal Kubecek };
106a94b8ccSMichal Kubecek 
116a94b8ccSMichal Kubecek struct debug_reply_data {
126a94b8ccSMichal Kubecek 	struct ethnl_reply_data		base;
136a94b8ccSMichal Kubecek 	u32				msg_mask;
146a94b8ccSMichal Kubecek };
156a94b8ccSMichal Kubecek 
166a94b8ccSMichal Kubecek #define DEBUG_REPDATA(__reply_base) \
176a94b8ccSMichal Kubecek 	container_of(__reply_base, struct debug_reply_data, base)
186a94b8ccSMichal Kubecek 
19ff419afaSJakub Kicinski const struct nla_policy ethnl_debug_get_policy[] = {
20329d9c33SJakub Kicinski 	[ETHTOOL_A_DEBUG_HEADER]	=
21329d9c33SJakub Kicinski 		NLA_POLICY_NESTED(ethnl_header_policy),
226a94b8ccSMichal Kubecek };
236a94b8ccSMichal Kubecek 
debug_prepare_data(const struct ethnl_req_info * req_base,struct ethnl_reply_data * reply_base,const struct genl_info * info)246a94b8ccSMichal Kubecek static int debug_prepare_data(const struct ethnl_req_info *req_base,
256a94b8ccSMichal Kubecek 			      struct ethnl_reply_data *reply_base,
26*f946270dSJakub Kicinski 			      const struct genl_info *info)
276a94b8ccSMichal Kubecek {
286a94b8ccSMichal Kubecek 	struct debug_reply_data *data = DEBUG_REPDATA(reply_base);
296a94b8ccSMichal Kubecek 	struct net_device *dev = reply_base->dev;
306a94b8ccSMichal Kubecek 	int ret;
316a94b8ccSMichal Kubecek 
326a94b8ccSMichal Kubecek 	if (!dev->ethtool_ops->get_msglevel)
336a94b8ccSMichal Kubecek 		return -EOPNOTSUPP;
346a94b8ccSMichal Kubecek 
356a94b8ccSMichal Kubecek 	ret = ethnl_ops_begin(dev);
366a94b8ccSMichal Kubecek 	if (ret < 0)
376a94b8ccSMichal Kubecek 		return ret;
386a94b8ccSMichal Kubecek 	data->msg_mask = dev->ethtool_ops->get_msglevel(dev);
396a94b8ccSMichal Kubecek 	ethnl_ops_complete(dev);
406a94b8ccSMichal Kubecek 
416a94b8ccSMichal Kubecek 	return 0;
426a94b8ccSMichal Kubecek }
436a94b8ccSMichal Kubecek 
debug_reply_size(const struct ethnl_req_info * req_base,const struct ethnl_reply_data * reply_base)446a94b8ccSMichal Kubecek static int debug_reply_size(const struct ethnl_req_info *req_base,
456a94b8ccSMichal Kubecek 			    const struct ethnl_reply_data *reply_base)
466a94b8ccSMichal Kubecek {
476a94b8ccSMichal Kubecek 	const struct debug_reply_data *data = DEBUG_REPDATA(reply_base);
486a94b8ccSMichal Kubecek 	bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
496a94b8ccSMichal Kubecek 
506a94b8ccSMichal Kubecek 	return ethnl_bitset32_size(&data->msg_mask, NULL, NETIF_MSG_CLASS_COUNT,
516a94b8ccSMichal Kubecek 				   netif_msg_class_names, compact);
526a94b8ccSMichal Kubecek }
536a94b8ccSMichal Kubecek 
debug_fill_reply(struct sk_buff * skb,const struct ethnl_req_info * req_base,const struct ethnl_reply_data * reply_base)546a94b8ccSMichal Kubecek static int debug_fill_reply(struct sk_buff *skb,
556a94b8ccSMichal Kubecek 			    const struct ethnl_req_info *req_base,
566a94b8ccSMichal Kubecek 			    const struct ethnl_reply_data *reply_base)
576a94b8ccSMichal Kubecek {
586a94b8ccSMichal Kubecek 	const struct debug_reply_data *data = DEBUG_REPDATA(reply_base);
596a94b8ccSMichal Kubecek 	bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
606a94b8ccSMichal Kubecek 
616a94b8ccSMichal Kubecek 	return ethnl_put_bitset32(skb, ETHTOOL_A_DEBUG_MSGMASK, &data->msg_mask,
626a94b8ccSMichal Kubecek 				  NULL, NETIF_MSG_CLASS_COUNT,
636a94b8ccSMichal Kubecek 				  netif_msg_class_names, compact);
646a94b8ccSMichal Kubecek }
656a94b8ccSMichal Kubecek 
6604007961SJakub Kicinski /* DEBUG_SET */
6704007961SJakub Kicinski 
6804007961SJakub Kicinski const struct nla_policy ethnl_debug_set_policy[] = {
6904007961SJakub Kicinski 	[ETHTOOL_A_DEBUG_HEADER]	=
7004007961SJakub Kicinski 		NLA_POLICY_NESTED(ethnl_header_policy),
7104007961SJakub Kicinski 	[ETHTOOL_A_DEBUG_MSGMASK]	= { .type = NLA_NESTED },
7204007961SJakub Kicinski };
7304007961SJakub Kicinski 
7404007961SJakub Kicinski static int
ethnl_set_debug_validate(struct ethnl_req_info * req_info,struct genl_info * info)7504007961SJakub Kicinski ethnl_set_debug_validate(struct ethnl_req_info *req_info,
7604007961SJakub Kicinski 			 struct genl_info *info)
7704007961SJakub Kicinski {
7804007961SJakub Kicinski 	const struct ethtool_ops *ops = req_info->dev->ethtool_ops;
7904007961SJakub Kicinski 
8004007961SJakub Kicinski 	return ops->get_msglevel && ops->set_msglevel ? 1 : -EOPNOTSUPP;
8104007961SJakub Kicinski }
8204007961SJakub Kicinski 
8304007961SJakub Kicinski static int
ethnl_set_debug(struct ethnl_req_info * req_info,struct genl_info * info)8404007961SJakub Kicinski ethnl_set_debug(struct ethnl_req_info *req_info, struct genl_info *info)
8504007961SJakub Kicinski {
8604007961SJakub Kicinski 	struct net_device *dev = req_info->dev;
8704007961SJakub Kicinski 	struct nlattr **tb = info->attrs;
8804007961SJakub Kicinski 	bool mod = false;
8904007961SJakub Kicinski 	u32 msg_mask;
9004007961SJakub Kicinski 	int ret;
9104007961SJakub Kicinski 
9204007961SJakub Kicinski 	msg_mask = dev->ethtool_ops->get_msglevel(dev);
9304007961SJakub Kicinski 	ret = ethnl_update_bitset32(&msg_mask, NETIF_MSG_CLASS_COUNT,
9404007961SJakub Kicinski 				    tb[ETHTOOL_A_DEBUG_MSGMASK],
9504007961SJakub Kicinski 				    netif_msg_class_names, info->extack, &mod);
9604007961SJakub Kicinski 	if (ret < 0 || !mod)
9704007961SJakub Kicinski 		return ret;
9804007961SJakub Kicinski 
9904007961SJakub Kicinski 	dev->ethtool_ops->set_msglevel(dev, msg_mask);
10004007961SJakub Kicinski 	return 1;
10104007961SJakub Kicinski }
10204007961SJakub Kicinski 
1036a94b8ccSMichal Kubecek const struct ethnl_request_ops ethnl_debug_request_ops = {
1046a94b8ccSMichal Kubecek 	.request_cmd		= ETHTOOL_MSG_DEBUG_GET,
1056a94b8ccSMichal Kubecek 	.reply_cmd		= ETHTOOL_MSG_DEBUG_GET_REPLY,
1066a94b8ccSMichal Kubecek 	.hdr_attr		= ETHTOOL_A_DEBUG_HEADER,
1076a94b8ccSMichal Kubecek 	.req_info_size		= sizeof(struct debug_req_info),
1086a94b8ccSMichal Kubecek 	.reply_data_size	= sizeof(struct debug_reply_data),
1096a94b8ccSMichal Kubecek 
1106a94b8ccSMichal Kubecek 	.prepare_data		= debug_prepare_data,
1116a94b8ccSMichal Kubecek 	.reply_size		= debug_reply_size,
1126a94b8ccSMichal Kubecek 	.fill_reply		= debug_fill_reply,
11304007961SJakub Kicinski 
11404007961SJakub Kicinski 	.set_validate		= ethnl_set_debug_validate,
11504007961SJakub Kicinski 	.set			= ethnl_set_debug,
11604007961SJakub Kicinski 	.set_ntf_cmd		= ETHTOOL_MSG_DEBUG_NTF,
1176a94b8ccSMichal Kubecek };
118