Some PHYs can do more than just measure the distance to a fault. But these additional actions are expensive. So allow options to be passed to enable these additional actions.
Signed-off-by: Andrew Lunn <and...@lunn.ch> --- drivers/net/phy/marvell.c | 6 +++++- drivers/net/phy/phy.c | 5 +++-- include/linux/phy.h | 7 ++++--- include/uapi/linux/ethtool_netlink.h | 1 + net/ethtool/actions.c | 10 ++++++++-- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 96354513daba..11a19c354533 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1667,10 +1667,14 @@ static void marvell_get_stats(struct phy_device *phydev, data[i] = marvell_get_stat(phydev, i); } -static int marvell_vct7_cable_test_start(struct phy_device *phydev) +static int marvell_vct7_cable_test_start(struct phy_device *phydev, + int options) { int bmcr, bmsr, ret; + if (options) + return -EOPNOTSUPP; + /* If auto-negotiation is enabled, but not complete, the cable test never completes. So disable auto-neg. */ diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 6540523d773a..38a766fc0923 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -533,7 +533,8 @@ int phy_cable_test_fault_length(struct phy_device *phydev, u8 pair, u16 cm) EXPORT_SYMBOL_GPL(phy_cable_test_fault_length); int phy_start_cable_test(struct phy_device *phydev, - struct netlink_ext_ack *extack, u32 seq) + struct netlink_ext_ack *extack, u32 seq, + int options) { int err = -ENOMEM; int ret; @@ -577,7 +578,7 @@ int phy_start_cable_test(struct phy_device *phydev, /* Mark the carrier down until the test is complete */ phy_link_down(phydev, true); - err = phydev->drv->cable_test_start(phydev); + err = phydev->drv->cable_test_start(phydev, options); if (err) { phy_link_up(phydev); goto out_free; diff --git a/include/linux/phy.h b/include/linux/phy.h index 23c18583ea07..2ef7dc37ea44 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -641,7 +641,7 @@ struct phy_driver { struct ethtool_eeprom *ee, u8 *data); /* Start a cable test */ - int (*cable_test_start)(struct phy_device *dev); + int (*cable_test_start)(struct phy_device *dev, int options); /* Once per second, or on interrupt, request the status of the * test. */ @@ -1078,12 +1078,12 @@ int phy_reset_after_clk_enable(struct phy_device *phydev); #if IS_ENABLED(CONFIG_PHYLIB) int phy_start_cable_test(struct phy_device *phydev, struct netlink_ext_ack *extack, - u32 seq); + u32 seq, int options); #else static inline int phy_start_cable_test(struct phy_device *phydev, struct netlink_ext_ack *extack, - u32 seq) + u32 seq, int options) { NL_SET_ERR_MSG(extack, "Kernel not compiled with PHYLIB support"); return -EOPNOTSUPP; @@ -1093,6 +1093,7 @@ int phy_start_cable_test(struct phy_device *phydev, int phy_cable_test_result(struct phy_device *phydev, u8 pair, u16 result); int phy_cable_test_fault_length(struct phy_device *phydev, u8 pair, u16 cm); +#define PHY_CABLE_TEST_AMPLITUDE_GRAPH BIT(0) static inline void phy_device_reset(struct phy_device *phydev, int value) { diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index aac76a26f97b..841f23ca2306 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -565,6 +565,7 @@ enum { enum { ETHTOOL_A_CABLE_TEST_UNSPEC, ETHTOOL_A_CABLE_TEST_DEV, /* nest - ETHTOOL_A_DEV_* */ + ETHTOOL_A_CABLE_TEST_AMPLITUDE_GRAPH, __ETHTOOL_A_CABLE_TEST_CNT, ETHTOOL_A_CABLE_TEST_MAX = (__ETHTOOL_A_CABLE_TEST_CNT - 1) diff --git a/net/ethtool/actions.c b/net/ethtool/actions.c index 8595cc27d532..12ff93c526f0 100644 --- a/net/ethtool/actions.c +++ b/net/ethtool/actions.c @@ -382,7 +382,8 @@ int ethnl_act_reset(struct sk_buff *skb, struct genl_info *info) static const struct nla_policy cable_test_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = { [ETHTOOL_A_CABLE_TEST_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_CABLE_TEST_DEV] = { .type = NLA_NESTED }, + [ETHTOOL_A_CABLE_TEST_DEV] = { .type = NLA_NESTED }, + [ETHTOOL_A_CABLE_TEST_AMPLITUDE_GRAPH] = { .type = NLA_FLAG }, }; void ethnl_cable_test_notify(struct net_device *dev, @@ -418,6 +419,7 @@ void ethnl_cable_test_notify(struct net_device *dev, int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) { struct nlattr *tb[ETHTOOL_A_CABLE_TEST_MAX + 1]; + int options = 0; struct net_device *dev; int ret; @@ -435,12 +437,16 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) if (!dev->phydev) goto out_dev; + if (tb[ETHTOOL_A_CABLE_TEST_AMPLITUDE_GRAPH]) + options = PHY_CABLE_TEST_AMPLITUDE_GRAPH; + rtnl_lock(); ret = ethnl_before_ops(dev); if (ret < 0) goto out_rtnl; - ret = phy_start_cable_test(dev->phydev, info->extack, info->snd_seq); + ret = phy_start_cable_test(dev->phydev, info->extack, info->snd_seq, + options); ethnl_after_ops(dev); -- 2.20.1