1 // SPDX-License-Identifier: GPL-2.0-only
4 #include <linux/ethtool_netlink.h>
10 static const struct nla_policy
11 cable_test_act_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = {
12 [ETHTOOL_A_CABLE_TEST_UNSPEC] = { .type = NLA_REJECT },
13 [ETHTOOL_A_CABLE_TEST_HEADER] = { .type = NLA_NESTED },
16 static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd)
22 skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
26 ehdr = ethnl_bcastmsg_put(skb, cmd);
32 err = ethnl_fill_reply_header(skb, phydev->attached_dev,
33 ETHTOOL_A_CABLE_TEST_NTF_HEADER);
37 err = nla_put_u8(skb, ETHTOOL_A_CABLE_TEST_NTF_STATUS,
38 ETHTOOL_A_CABLE_TEST_NTF_STATUS_STARTED);
42 genlmsg_end(skb, ehdr);
44 return ethnl_multicast(skb, phydev->attached_dev);
48 phydev_err(phydev, "%s: Error %pe\n", __func__, ERR_PTR(err));
53 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
55 struct nlattr *tb[ETHTOOL_A_CABLE_TEST_MAX + 1];
56 struct ethnl_req_info req_info = {};
57 struct net_device *dev;
60 ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
61 ETHTOOL_A_CABLE_TEST_MAX,
62 cable_test_act_policy, info->extack);
66 ret = ethnl_parse_header_dev_get(&req_info,
67 tb[ETHTOOL_A_CABLE_TEST_HEADER],
68 genl_info_net(info), info->extack,
80 ret = ethnl_ops_begin(dev);
84 ret = phy_start_cable_test(dev->phydev, info->extack);
86 ethnl_ops_complete(dev);
89 ethnl_cable_test_started(dev->phydev,
90 ETHTOOL_MSG_CABLE_TEST_NTF);
99 int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd)
103 /* One TDR sample occupies 20 bytes. For a 150 meter cable,
104 * with four pairs, around 12K is needed.
106 phydev->skb = genlmsg_new(SZ_16K, GFP_KERNEL);
110 phydev->ehdr = ethnl_bcastmsg_put(phydev->skb, cmd);
116 err = ethnl_fill_reply_header(phydev->skb, phydev->attached_dev,
117 ETHTOOL_A_CABLE_TEST_NTF_HEADER);
121 err = nla_put_u8(phydev->skb, ETHTOOL_A_CABLE_TEST_NTF_STATUS,
122 ETHTOOL_A_CABLE_TEST_NTF_STATUS_COMPLETED);
126 phydev->nest = nla_nest_start(phydev->skb,
127 ETHTOOL_A_CABLE_TEST_NTF_NEST);
136 nlmsg_free(phydev->skb);
140 EXPORT_SYMBOL_GPL(ethnl_cable_test_alloc);
142 void ethnl_cable_test_free(struct phy_device *phydev)
144 nlmsg_free(phydev->skb);
147 EXPORT_SYMBOL_GPL(ethnl_cable_test_free);
149 void ethnl_cable_test_finished(struct phy_device *phydev)
151 nla_nest_end(phydev->skb, phydev->nest);
153 genlmsg_end(phydev->skb, phydev->ehdr);
155 ethnl_multicast(phydev->skb, phydev->attached_dev);
157 EXPORT_SYMBOL_GPL(ethnl_cable_test_finished);
159 int ethnl_cable_test_result(struct phy_device *phydev, u8 pair, u8 result)
164 nest = nla_nest_start(phydev->skb, ETHTOOL_A_CABLE_NEST_RESULT);
168 if (nla_put_u8(phydev->skb, ETHTOOL_A_CABLE_RESULT_PAIR, pair))
170 if (nla_put_u8(phydev->skb, ETHTOOL_A_CABLE_RESULT_CODE, result))
173 nla_nest_end(phydev->skb, nest);
177 nla_nest_cancel(phydev->skb, nest);
180 EXPORT_SYMBOL_GPL(ethnl_cable_test_result);
182 int ethnl_cable_test_fault_length(struct phy_device *phydev, u8 pair, u32 cm)
187 nest = nla_nest_start(phydev->skb,
188 ETHTOOL_A_CABLE_NEST_FAULT_LENGTH);
192 if (nla_put_u8(phydev->skb, ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR, pair))
194 if (nla_put_u32(phydev->skb, ETHTOOL_A_CABLE_FAULT_LENGTH_CM, cm))
197 nla_nest_end(phydev->skb, nest);
201 nla_nest_cancel(phydev->skb, nest);
204 EXPORT_SYMBOL_GPL(ethnl_cable_test_fault_length);
206 static const struct nla_policy
207 cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1] = {
208 [ETHTOOL_A_CABLE_TEST_TDR_UNSPEC] = { .type = NLA_REJECT },
209 [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = { .type = NLA_NESTED },
212 int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
214 struct nlattr *tb[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1];
215 struct ethnl_req_info req_info = {};
216 struct net_device *dev;
219 ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
220 ETHTOOL_A_CABLE_TEST_TDR_MAX,
221 cable_test_tdr_act_policy, info->extack);
225 ret = ethnl_parse_header_dev_get(&req_info,
226 tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
227 genl_info_net(info), info->extack,
239 ret = ethnl_ops_begin(dev);
243 ret = phy_start_cable_test_tdr(dev->phydev, info->extack);
245 ethnl_ops_complete(dev);
248 ethnl_cable_test_started(dev->phydev,
249 ETHTOOL_MSG_CABLE_TEST_TDR_NTF);
258 int ethnl_cable_test_amplitude(struct phy_device *phydev,
264 nest = nla_nest_start(phydev->skb,
265 ETHTOOL_A_CABLE_TDR_NEST_AMPLITUDE);
269 if (nla_put_u8(phydev->skb, ETHTOOL_A_CABLE_AMPLITUDE_PAIR, pair))
271 if (nla_put_u16(phydev->skb, ETHTOOL_A_CABLE_AMPLITUDE_mV, mV))
274 nla_nest_end(phydev->skb, nest);
278 nla_nest_cancel(phydev->skb, nest);
281 EXPORT_SYMBOL_GPL(ethnl_cable_test_amplitude);
283 int ethnl_cable_test_pulse(struct phy_device *phydev, u16 mV)
288 nest = nla_nest_start(phydev->skb, ETHTOOL_A_CABLE_TDR_NEST_PULSE);
292 if (nla_put_u16(phydev->skb, ETHTOOL_A_CABLE_PULSE_mV, mV))
295 nla_nest_end(phydev->skb, nest);
299 nla_nest_cancel(phydev->skb, nest);
302 EXPORT_SYMBOL_GPL(ethnl_cable_test_pulse);
304 int ethnl_cable_test_step(struct phy_device *phydev, u32 first, u32 last,
310 nest = nla_nest_start(phydev->skb, ETHTOOL_A_CABLE_TDR_NEST_STEP);
314 if (nla_put_u32(phydev->skb, ETHTOOL_A_CABLE_STEP_FIRST_DISTANCE,
318 if (nla_put_u32(phydev->skb, ETHTOOL_A_CABLE_STEP_LAST_DISTANCE, last))
321 if (nla_put_u32(phydev->skb, ETHTOOL_A_CABLE_STEP_STEP_DISTANCE, step))
324 nla_nest_end(phydev->skb, nest);
328 nla_nest_cancel(phydev->skb, nest);
331 EXPORT_SYMBOL_GPL(ethnl_cable_test_step);