History

net: ethtool: Add generic parts of cable test TDR

Add the generic parts of the code used to trigger a cable test and return raw TDR data. Any PHY driver which support this must implement the new driver op. Signed-off-by: Andrew Lunn <andrew@lunn.ch> v2 Update nxp-tja11xx for API change.

Andrew Lunn committed 6 years ago

Commit 1a644de1 parent a3311727 files · +144 −10Browse files

Unified · Split

7 files
  1. drivers/net/phy/nxp-tja11xx.c +1 −1
  2. drivers/net/phy/phy.c +64 −1
  3. include/linux/ethtool_netlink.h +2 −2
  4. include/linux/phy.h +13 −0
  5. net/ethtool/cabletest.c +58 −6
  6. net/ethtool/netlink.c +5 −0
  7. net/ethtool/netlink.h +1 −0
drivers/net/phy/nxp-tja11xx.c+1−1
@@ -194,7 +194,7 @@ static int tja11xx_config_aneg_cable_test(struct phy_device *phydev) · 193 unmodified lines
194 !phydev->drv->cable_test_get_status)194 !phydev->drv->cable_test_get_status)
195 return 0;195 return 0;
196 196
197 ret = ethnl_cable_test_alloc(phydev);197 ret = ethnl_cable_test_alloc(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
198 if (ret)198 if (ret)
199 return ret;199 return ret;
200 200
drivers/net/phy/phy.c+64−1
@@ -519,7 +519,7 @@ int phy_start_cable_test(struct phy_device *phydev, · 518 unmodified lines
519 goto out;519 goto out;
520 }520 }
521 521
522 err = ethnl_cable_test_alloc(phydev);522 err = ethnl_cable_test_alloc(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
523 if (err)523 if (err)
524 goto out;524 goto out;
525 525
@@ -552,6 +552,69 @@ out: · 26 unmodified lines
552}552}
553EXPORT_SYMBOL(phy_start_cable_test);553EXPORT_SYMBOL(phy_start_cable_test);
554 554
555int phy_start_cable_test_tdr(struct phy_device *phydev,
556 struct netlink_ext_ack *extack)
557{
558 struct net_device *dev = phydev->attached_dev;
559 int err = -ENOMEM;
560
561 if (!(phydev->drv &&
562 phydev->drv->cable_test_tdr_start &&
563 phydev->drv->cable_test_get_status)) {
564 NL_SET_ERR_MSG(extack,
565 "PHY driver does not support cable test TDR");
566 return -EOPNOTSUPP;
567 }
568
569 mutex_lock(&phydev->lock);
570 if (phydev->state == PHY_CABLETEST) {
571 NL_SET_ERR_MSG(extack,
572 "PHY already performing a test");
573 err = -EBUSY;
574 goto out;
575 }
576
577 if (phydev->state < PHY_UP ||
578 phydev->state > PHY_CABLETEST) {
579 NL_SET_ERR_MSG(extack,
580 "PHY not configured. Try setting interface up");
581 err = -EBUSY;
582 goto out;
583 }
584
585 err = ethnl_cable_test_alloc(phydev, ETHTOOL_MSG_CABLE_TEST_TDR_NTF);
586 if (err)
587 goto out;
588
589 /* Mark the carrier down until the test is complete */
590 phy_link_down(phydev);
591
592 netif_testing_on(dev);
593 err = phydev->drv->cable_test_tdr_start(phydev);
594 if (err) {
595 netif_testing_off(dev);
596 phy_link_up(phydev);
597 goto out_free;
598 }
599
600 phydev->state = PHY_CABLETEST;
601
602 if (phy_polling_mode(phydev))
603 phy_trigger_machine(phydev);
604
605 mutex_unlock(&phydev->lock);
606
607 return 0;
608
609out_free:
610 ethnl_cable_test_free(phydev);
611out:
612 mutex_unlock(&phydev->lock);
613
614 return err;
615}
616EXPORT_SYMBOL(phy_start_cable_test_tdr);
617
555static int phy_config_aneg(struct phy_device *phydev)618static int phy_config_aneg(struct phy_device *phydev)
556{619{
557 if (phydev->drv->config_aneg)620 if (phydev->drv->config_aneg)
include/linux/ethtool_netlink.h+2−2
@@ -17,13 +17,13 @@ enum ethtool_multicast_groups { · 16 unmodified lines
17struct phy_device;17struct phy_device;
18 18
19#if IS_ENABLED(CONFIG_ETHTOOL_NETLINK)19#if IS_ENABLED(CONFIG_ETHTOOL_NETLINK)
20int ethnl_cable_test_alloc(struct phy_device *phydev);20int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd);
21void ethnl_cable_test_free(struct phy_device *phydev);21void ethnl_cable_test_free(struct phy_device *phydev);
22void ethnl_cable_test_finished(struct phy_device *phydev);22void ethnl_cable_test_finished(struct phy_device *phydev);
23int ethnl_cable_test_result(struct phy_device *phydev, u8 pair, u8 result);23int ethnl_cable_test_result(struct phy_device *phydev, u8 pair, u8 result);
24int ethnl_cable_test_fault_length(struct phy_device *phydev, u8 pair, u32 cm);24int ethnl_cable_test_fault_length(struct phy_device *phydev, u8 pair, u32 cm);
25#else25#else
26static inline int ethnl_cable_test_alloc(struct phy_device *phydev)26static inline int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd)
27{27{
28 return -EOPNOTSUPP;28 return -EOPNOTSUPP;
29}29}
include/linux/phy.h+13−0
@@ -699,6 +699,10 @@ struct phy_driver { · 698 unmodified lines
699 699
700 /* Start a cable test */700 /* Start a cable test */
701 int (*cable_test_start)(struct phy_device *dev);701 int (*cable_test_start)(struct phy_device *dev);
702
703 /* Start a raw TDR cable test */
704 int (*cable_test_tdr_start)(struct phy_device *dev);
705
702 /* Once per second, or on interrupt, request the status of the706 /* Once per second, or on interrupt, request the status of the
703 * test.707 * test.
704 */708 */
@@ -1251,6 +1255,8 @@ int phy_reset_after_clk_enable(struct phy_device *phydev); · 546 unmodified lines
1251#if IS_ENABLED(CONFIG_PHYLIB)1255#if IS_ENABLED(CONFIG_PHYLIB)
1252int phy_start_cable_test(struct phy_device *phydev,1256int phy_start_cable_test(struct phy_device *phydev,
1253 struct netlink_ext_ack *extack);1257 struct netlink_ext_ack *extack);
1258int phy_start_cable_test_tdr(struct phy_device *phydev,
1259 struct netlink_ext_ack *extack);
1254#else1260#else
1255static inline1261static inline
1256int phy_start_cable_test(struct phy_device *phydev,1262int phy_start_cable_test(struct phy_device *phydev,
@@ -1259,6 +1265,13 @@ int phy_start_cable_test(struct phy_device *phydev, · 2 unmodified lines
1259 NL_SET_ERR_MSG(extack, "Kernel not compiled with PHYLIB support");1265 NL_SET_ERR_MSG(extack, "Kernel not compiled with PHYLIB support");
1260 return -EOPNOTSUPP;1266 return -EOPNOTSUPP;
1261}1267}
1268static inline
1269int phy_start_cable_test_tdr(struct phy_device *phydev,
1270 struct netlink_ext_ack *extack)
1271{
1272 NL_SET_ERR_MSG(extack, "Kernel not compiled with PHYLIB support");
1273 return -EOPNOTSUPP;
1274}
1262#endif1275#endif
1263 1276
1264int phy_cable_test_result(struct phy_device *phydev, u8 pair, u16 result);1277int phy_cable_test_result(struct phy_device *phydev, u8 pair, u16 result);
net/ethtool/cabletest.c+58−6
@@ -13,7 +13,7 @@ cable_test_act_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = { · 12 unmodified lines
13 [ETHTOOL_A_CABLE_TEST_HEADER] = { .type = NLA_NESTED },13 [ETHTOOL_A_CABLE_TEST_HEADER] = { .type = NLA_NESTED },
14};14};
15 15
16static int ethnl_cable_test_started(struct phy_device *phydev)16static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd)
17{17{
18 struct sk_buff *skb;18 struct sk_buff *skb;
19 int err = -ENOMEM;19 int err = -ENOMEM;
@@ -23,7 +23,7 @@ static int ethnl_cable_test_started(struct phy_device *phydev) · 3 unmodified lines
23 if (!skb)23 if (!skb)
24 goto out;24 goto out;
25 25
26 ehdr = ethnl_bcastmsg_put(skb, ETHTOOL_MSG_CABLE_TEST_NTF);26 ehdr = ethnl_bcastmsg_put(skb, cmd);
27 if (!ehdr) {27 if (!ehdr) {
28 err = -EMSGSIZE;28 err = -EMSGSIZE;
29 goto out;29 goto out;
@@ -86,7 +86,8 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) · 56 unmodified lines
86 ethnl_ops_complete(dev);86 ethnl_ops_complete(dev);
87 87
88 if (!ret)88 if (!ret)
89 ethnl_cable_test_started(dev->phydev);89 ethnl_cable_test_started(dev->phydev,
90 ETHTOOL_MSG_CABLE_TEST_NTF);
90 91
91out_rtnl:92out_rtnl:
92 rtnl_unlock();93 rtnl_unlock();
@@ -95,7 +96,7 @@ out_dev_put: · 2 unmodified lines
95 return ret;96 return ret;
96}97}
97 98
98int ethnl_cable_test_alloc(struct phy_device *phydev)99int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd)
99{100{
100 int err = -ENOMEM;101 int err = -ENOMEM;
101 102
@@ -103,8 +104,7 @@ int ethnl_cable_test_alloc(struct phy_device *phydev) · 1 unmodified line
103 if (!phydev->skb)104 if (!phydev->skb)
104 goto out;105 goto out;
105 106
106 phydev->ehdr = ethnl_bcastmsg_put(phydev->skb,107 phydev->ehdr = ethnl_bcastmsg_put(phydev->skb, cmd);
107 ETHTOOL_MSG_CABLE_TEST_NTF);
108 if (!phydev->ehdr) {108 if (!phydev->ehdr) {
109 err = -EMSGSIZE;109 err = -EMSGSIZE;
110 goto out;110 goto out;
@@ -199,3 +199,55 @@ err: · 88 unmodified lines
199 return ret;199 return ret;
200}200}
201EXPORT_SYMBOL_GPL(ethnl_cable_test_fault_length);201EXPORT_SYMBOL_GPL(ethnl_cable_test_fault_length);
202
203static const struct nla_policy
204cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1] = {
205 [ETHTOOL_A_CABLE_TEST_TDR_UNSPEC] = { .type = NLA_REJECT },
206 [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = { .type = NLA_NESTED },
207};
208
209int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
210{
211 struct nlattr *tb[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1];
212 struct ethnl_req_info req_info = {};
213 struct net_device *dev;
214 int ret;
215
216 ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
217 ETHTOOL_A_CABLE_TEST_TDR_MAX,
218 cable_test_tdr_act_policy, info->extack);
219 if (ret < 0)
220 return ret;
221
222 ret = ethnl_parse_header_dev_get(&req_info,
223 tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
224 genl_info_net(info), info->extack,
225 true);
226 if (ret < 0)
227 return ret;
228
229 dev = req_info.dev;
230 if (!dev->phydev) {
231 ret = -EOPNOTSUPP;
232 goto out_dev_put;
233 }
234
235 rtnl_lock();
236 ret = ethnl_ops_begin(dev);
237 if (ret < 0)
238 goto out_rtnl;
239
240 ret = phy_start_cable_test_tdr(dev->phydev, info->extack);
241
242 ethnl_ops_complete(dev);
243
244 if (!ret)
245 ethnl_cable_test_started(dev->phydev,
246 ETHTOOL_MSG_CABLE_TEST_TDR_NTF);
247
248out_rtnl:
249 rtnl_unlock();
250out_dev_put:
251 dev_put(dev);
252 return ret;
253}
net/ethtool/netlink.c+5−0
@@ -844,6 +844,11 @@ static const struct genl_ops ethtool_genl_ops[] = { · 843 unmodified lines
844 .flags = GENL_UNS_ADMIN_PERM,844 .flags = GENL_UNS_ADMIN_PERM,
845 .doit = ethnl_act_cable_test,845 .doit = ethnl_act_cable_test,
846 },846 },
847 {
848 .cmd = ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
849 .flags = GENL_UNS_ADMIN_PERM,
850 .doit = ethnl_act_cable_test_tdr,
851 },
847};852};
848 853
849static const struct genl_multicast_group ethtool_nl_mcgrps[] = {854static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
net/ethtool/netlink.h+1−0
@@ -360,5 +360,6 @@ int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info); · 359 unmodified lines
360int ethnl_set_pause(struct sk_buff *skb, struct genl_info *info);360int ethnl_set_pause(struct sk_buff *skb, struct genl_info *info);
361int ethnl_set_eee(struct sk_buff *skb, struct genl_info *info);361int ethnl_set_eee(struct sk_buff *skb, struct genl_info *info);
362int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);362int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
363int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info);
363 364
364#endif /* _NET_ETHTOOL_NETLINK_H */365#endif /* _NET_ETHTOOL_NETLINK_H */