@@ -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.
*/
@@ -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;
@@ -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)
{
@@ -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)
@@ -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);
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 <andrew@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(-)