xref: /openbmc/linux/net/ethtool/cabletest.c (revision 11ca3c42)
111ca3c42SAndrew Lunn // SPDX-License-Identifier: GPL-2.0-only
211ca3c42SAndrew Lunn 
311ca3c42SAndrew Lunn #include <linux/phy.h>
411ca3c42SAndrew Lunn #include "netlink.h"
511ca3c42SAndrew Lunn #include "common.h"
611ca3c42SAndrew Lunn 
711ca3c42SAndrew Lunn /* CABLE_TEST_ACT */
811ca3c42SAndrew Lunn 
911ca3c42SAndrew Lunn static const struct nla_policy
1011ca3c42SAndrew Lunn cable_test_act_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = {
1111ca3c42SAndrew Lunn 	[ETHTOOL_A_CABLE_TEST_UNSPEC]		= { .type = NLA_REJECT },
1211ca3c42SAndrew Lunn 	[ETHTOOL_A_CABLE_TEST_HEADER]		= { .type = NLA_NESTED },
1311ca3c42SAndrew Lunn };
1411ca3c42SAndrew Lunn 
1511ca3c42SAndrew Lunn int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
1611ca3c42SAndrew Lunn {
1711ca3c42SAndrew Lunn 	struct nlattr *tb[ETHTOOL_A_CABLE_TEST_MAX + 1];
1811ca3c42SAndrew Lunn 	struct ethnl_req_info req_info = {};
1911ca3c42SAndrew Lunn 	struct net_device *dev;
2011ca3c42SAndrew Lunn 	int ret;
2111ca3c42SAndrew Lunn 
2211ca3c42SAndrew Lunn 	ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
2311ca3c42SAndrew Lunn 			  ETHTOOL_A_CABLE_TEST_MAX,
2411ca3c42SAndrew Lunn 			  cable_test_act_policy, info->extack);
2511ca3c42SAndrew Lunn 	if (ret < 0)
2611ca3c42SAndrew Lunn 		return ret;
2711ca3c42SAndrew Lunn 
2811ca3c42SAndrew Lunn 	ret = ethnl_parse_header_dev_get(&req_info,
2911ca3c42SAndrew Lunn 					 tb[ETHTOOL_A_CABLE_TEST_HEADER],
3011ca3c42SAndrew Lunn 					 genl_info_net(info), info->extack,
3111ca3c42SAndrew Lunn 					 true);
3211ca3c42SAndrew Lunn 	if (ret < 0)
3311ca3c42SAndrew Lunn 		return ret;
3411ca3c42SAndrew Lunn 
3511ca3c42SAndrew Lunn 	dev = req_info.dev;
3611ca3c42SAndrew Lunn 	if (!dev->phydev) {
3711ca3c42SAndrew Lunn 		ret = -EOPNOTSUPP;
3811ca3c42SAndrew Lunn 		goto out_dev_put;
3911ca3c42SAndrew Lunn 	}
4011ca3c42SAndrew Lunn 
4111ca3c42SAndrew Lunn 	rtnl_lock();
4211ca3c42SAndrew Lunn 	ret = ethnl_ops_begin(dev);
4311ca3c42SAndrew Lunn 	if (ret < 0)
4411ca3c42SAndrew Lunn 		goto out_rtnl;
4511ca3c42SAndrew Lunn 
4611ca3c42SAndrew Lunn 	ret = phy_start_cable_test(dev->phydev, info->extack);
4711ca3c42SAndrew Lunn 
4811ca3c42SAndrew Lunn 	ethnl_ops_complete(dev);
4911ca3c42SAndrew Lunn out_rtnl:
5011ca3c42SAndrew Lunn 	rtnl_unlock();
5111ca3c42SAndrew Lunn out_dev_put:
5211ca3c42SAndrew Lunn 	dev_put(dev);
5311ca3c42SAndrew Lunn 	return ret;
5411ca3c42SAndrew Lunn }
55