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
194194 !phydev->drv->cable_test_get_status)
195195 return 0;
196196
197− ret = ethnl_cable_test_alloc(phydev);
197+ ret = ethnl_cable_test_alloc(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
198198 if (ret)
199199 return ret;
200200
drivers/net/phy/phy.c+64−1
@@ -519,7 +519,7 @@ int phy_start_cable_test(struct phy_device *phydev, · 518 unmodified lines
519519 goto out;
520520 }
521521
522− err = ethnl_cable_test_alloc(phydev);
522+ err = ethnl_cable_test_alloc(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
523523 if (err)
524524 goto out;
525525
@@ -552,6 +552,69 @@ out: · 26 unmodified lines
552552 }
553553 EXPORT_SYMBOL(phy_start_cable_test);
554554
555+int 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+
609+out_free:
610+ ethnl_cable_test_free(phydev);
611+out:
612+ mutex_unlock(&phydev->lock);
613+
614+ return err;
615+}
616+EXPORT_SYMBOL(phy_start_cable_test_tdr);
617+
555618 static int phy_config_aneg(struct phy_device *phydev)
556619 {
557620 if (phydev->drv->config_aneg)
include/linux/ethtool_netlink.h+2−2
@@ -17,13 +17,13 @@ enum ethtool_multicast_groups { · 16 unmodified lines
1717 struct phy_device;
1818
1919 #if IS_ENABLED(CONFIG_ETHTOOL_NETLINK)
20−int ethnl_cable_test_alloc(struct phy_device *phydev);
20+int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd);
2121 void ethnl_cable_test_free(struct phy_device *phydev);
2222 void ethnl_cable_test_finished(struct phy_device *phydev);
2323 int ethnl_cable_test_result(struct phy_device *phydev, u8 pair, u8 result);
2424 int ethnl_cable_test_fault_length(struct phy_device *phydev, u8 pair, u32 cm);
2525 #else
26−static inline int ethnl_cable_test_alloc(struct phy_device *phydev)
26+static inline int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd)
2727 {
2828 return -EOPNOTSUPP;
2929 }
include/linux/phy.h+13−0
@@ -699,6 +699,10 @@ struct phy_driver { · 698 unmodified lines
699699
700700 /* Start a cable test */
701701 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+
702706 /* Once per second, or on interrupt, request the status of the
703707 * test.
704708 */
@@ -1251,6 +1255,8 @@ int phy_reset_after_clk_enable(struct phy_device *phydev); · 546 unmodified lines
12511255 #if IS_ENABLED(CONFIG_PHYLIB)
12521256 int phy_start_cable_test(struct phy_device *phydev,
12531257 struct netlink_ext_ack *extack);
1258+int phy_start_cable_test_tdr(struct phy_device *phydev,
1259+ struct netlink_ext_ack *extack);
12541260 #else
12551261 static inline
12561262 int phy_start_cable_test(struct phy_device *phydev,
@@ -1259,6 +1265,13 @@ int phy_start_cable_test(struct phy_device *phydev, · 2 unmodified lines
12591265 NL_SET_ERR_MSG(extack, "Kernel not compiled with PHYLIB support");
12601266 return -EOPNOTSUPP;
12611267 }
1268+static inline
1269+int 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+}
12621275 #endif
12631276
12641277 int 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
1313 [ETHTOOL_A_CABLE_TEST_HEADER] = { .type = NLA_NESTED },
1414 };
1515
16−static int ethnl_cable_test_started(struct phy_device *phydev)
16+static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd)
1717 {
1818 struct sk_buff *skb;
1919 int err = -ENOMEM;
@@ -23,7 +23,7 @@ static int ethnl_cable_test_started(struct phy_device *phydev) · 3 unmodified lines
2323 if (!skb)
2424 goto out;
2525
26− ehdr = ethnl_bcastmsg_put(skb, ETHTOOL_MSG_CABLE_TEST_NTF);
26+ ehdr = ethnl_bcastmsg_put(skb, cmd);
2727 if (!ehdr) {
2828 err = -EMSGSIZE;
2929 goto out;
@@ -86,7 +86,8 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) · 56 unmodified lines
8686 ethnl_ops_complete(dev);
8787
8888 if (!ret)
89− ethnl_cable_test_started(dev->phydev);
89+ ethnl_cable_test_started(dev->phydev,
90+ ETHTOOL_MSG_CABLE_TEST_NTF);
9091
9192 out_rtnl:
9293 rtnl_unlock();
@@ -95,7 +96,7 @@ out_dev_put: · 2 unmodified lines
9596 return ret;
9697 }
9798
98−int ethnl_cable_test_alloc(struct phy_device *phydev)
99+int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd)
99100 {
100101 int err = -ENOMEM;
101102
@@ -103,8 +104,7 @@ int ethnl_cable_test_alloc(struct phy_device *phydev) · 1 unmodified line
103104 if (!phydev->skb)
104105 goto out;
105106
106− phydev->ehdr = ethnl_bcastmsg_put(phydev->skb,
107− ETHTOOL_MSG_CABLE_TEST_NTF);
107+ phydev->ehdr = ethnl_bcastmsg_put(phydev->skb, cmd);
108108 if (!phydev->ehdr) {
109109 err = -EMSGSIZE;
110110 goto out;
@@ -199,3 +199,55 @@ err: · 88 unmodified lines
199199 return ret;
200200 }
201201 EXPORT_SYMBOL_GPL(ethnl_cable_test_fault_length);
202+
203+static const struct nla_policy
204+cable_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+
209+int 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+
248+out_rtnl:
249+ rtnl_unlock();
250+out_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
844844 .flags = GENL_UNS_ADMIN_PERM,
845845 .doit = ethnl_act_cable_test,
846846 },
847+ {
848+ .cmd = ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
849+ .flags = GENL_UNS_ADMIN_PERM,
850+ .doit = ethnl_act_cable_test_tdr,
851+ },
847852 };
848853
849854 static 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
360360 int ethnl_set_pause(struct sk_buff *skb, struct genl_info *info);
361361 int ethnl_set_eee(struct sk_buff *skb, struct genl_info *info);
362362 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
363+int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info);
363364
364365 #endif /* _NET_ETHTOOL_NETLINK_H */