Commit 417e19d1 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-ethtool-Untangle-PHYLIB-dependency'

Florian Fainelli says:

====================
net: ethtool: Untangle PHYLIB dependency

This patch series untangles the ethtool netlink dependency with PHYLIB
which exists because the cable test feature calls directly into PHY
library functions. The approach taken here is to introduce
ethtool_phy_ops function pointers which can be dynamically registered
when PHYLIB loads.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1a4d6816 f3631ab0
...@@ -3027,6 +3027,11 @@ static struct phy_driver genphy_driver = { ...@@ -3027,6 +3027,11 @@ static struct phy_driver genphy_driver = {
.set_loopback = genphy_loopback, .set_loopback = genphy_loopback,
}; };
static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
.start_cable_test = phy_start_cable_test,
.start_cable_test_tdr = phy_start_cable_test_tdr,
};
static int __init phy_init(void) static int __init phy_init(void)
{ {
int rc; int rc;
...@@ -3035,6 +3040,7 @@ static int __init phy_init(void) ...@@ -3035,6 +3040,7 @@ static int __init phy_init(void)
if (rc) if (rc)
return rc; return rc;
ethtool_set_ethtool_phy_ops(&phy_ethtool_phy_ops);
features_init(); features_init();
rc = phy_driver_register(&genphy_c45_driver, THIS_MODULE); rc = phy_driver_register(&genphy_c45_driver, THIS_MODULE);
...@@ -3056,6 +3062,7 @@ static void __exit phy_exit(void) ...@@ -3056,6 +3062,7 @@ static void __exit phy_exit(void)
phy_driver_unregister(&genphy_c45_driver); phy_driver_unregister(&genphy_c45_driver);
phy_driver_unregister(&genphy_driver); phy_driver_unregister(&genphy_driver);
mdio_bus_exit(); mdio_bus_exit();
ethtool_set_ethtool_phy_ops(NULL);
} }
subsys_initcall(phy_init); subsys_initcall(phy_init);
......
...@@ -502,5 +502,30 @@ int ethtool_virtdev_set_link_ksettings(struct net_device *dev, ...@@ -502,5 +502,30 @@ int ethtool_virtdev_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd, const struct ethtool_link_ksettings *cmd,
u32 *dev_speed, u8 *dev_duplex); u32 *dev_speed, u8 *dev_duplex);
struct netlink_ext_ack;
struct phy_device;
struct phy_tdr_config;
/**
* struct ethtool_phy_ops - Optional PHY device options
* @start_cable_test - Start a cable test
* @start_cable_test_tdr - Start a Time Domain Reflectometry cable test
*
* All operations are optional (i.e. the function pointer may be set to %NULL)
* and callers must take this into account. Callers must hold the RTNL lock.
*/
struct ethtool_phy_ops {
int (*start_cable_test)(struct phy_device *phydev,
struct netlink_ext_ack *extack);
int (*start_cable_test_tdr)(struct phy_device *phydev,
struct netlink_ext_ack *extack,
const struct phy_tdr_config *config);
};
/**
* ethtool_set_ethtool_phy_ops - Set the ethtool_phy_ops singleton
* @ops: Ethtool PHY operations to set
*/
void ethtool_set_ethtool_phy_ops(const struct ethtool_phy_ops *ops);
#endif /* _LINUX_ETHTOOL_H */ #endif /* _LINUX_ETHTOOL_H */
...@@ -455,7 +455,6 @@ config FAILOVER ...@@ -455,7 +455,6 @@ config FAILOVER
config ETHTOOL_NETLINK config ETHTOOL_NETLINK
bool "Netlink interface for ethtool" bool "Netlink interface for ethtool"
default y default y
depends on PHYLIB=y || PHYLIB=n
help help
An alternative userspace interface for ethtool based on generic An alternative userspace interface for ethtool based on generic
netlink. It provides better extensibility and some new features, netlink. It provides better extensibility and some new features,
......
...@@ -58,6 +58,7 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) ...@@ -58,6 +58,7 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
{ {
struct nlattr *tb[ETHTOOL_A_CABLE_TEST_MAX + 1]; struct nlattr *tb[ETHTOOL_A_CABLE_TEST_MAX + 1];
struct ethnl_req_info req_info = {}; struct ethnl_req_info req_info = {};
const struct ethtool_phy_ops *ops;
struct net_device *dev; struct net_device *dev;
int ret; int ret;
...@@ -81,11 +82,17 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) ...@@ -81,11 +82,17 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
} }
rtnl_lock(); rtnl_lock();
ops = ethtool_phy_ops;
if (!ops || !ops->start_cable_test) {
ret = -EOPNOTSUPP;
goto out_rtnl;
}
ret = ethnl_ops_begin(dev); ret = ethnl_ops_begin(dev);
if (ret < 0) if (ret < 0)
goto out_rtnl; goto out_rtnl;
ret = phy_start_cable_test(dev->phydev, info->extack); ret = ops->start_cable_test(dev->phydev, info->extack);
ethnl_ops_complete(dev); ethnl_ops_complete(dev);
...@@ -308,6 +315,7 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info) ...@@ -308,6 +315,7 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
{ {
struct nlattr *tb[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1]; struct nlattr *tb[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1];
struct ethnl_req_info req_info = {}; struct ethnl_req_info req_info = {};
const struct ethtool_phy_ops *ops;
struct phy_tdr_config cfg; struct phy_tdr_config cfg;
struct net_device *dev; struct net_device *dev;
int ret; int ret;
...@@ -337,11 +345,17 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info) ...@@ -337,11 +345,17 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
goto out_dev_put; goto out_dev_put;
rtnl_lock(); rtnl_lock();
ops = ethtool_phy_ops;
if (!ops || !ops->start_cable_test_tdr) {
ret = -EOPNOTSUPP;
goto out_rtnl;
}
ret = ethnl_ops_begin(dev); ret = ethnl_ops_begin(dev);
if (ret < 0) if (ret < 0)
goto out_rtnl; goto out_rtnl;
ret = phy_start_cable_test_tdr(dev->phydev, info->extack, &cfg); ret = ops->start_cable_test_tdr(dev->phydev, info->extack, &cfg);
ethnl_ops_complete(dev); ethnl_ops_complete(dev);
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include <linux/net_tstamp.h> #include <linux/net_tstamp.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/rtnetlink.h>
#include "common.h" #include "common.h"
...@@ -373,3 +374,13 @@ int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) ...@@ -373,3 +374,13 @@ int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
return 0; return 0;
} }
const struct ethtool_phy_ops *ethtool_phy_ops;
void ethtool_set_ethtool_phy_ops(const struct ethtool_phy_ops *ops)
{
rtnl_lock();
ethtool_phy_ops = ops;
rtnl_unlock();
}
EXPORT_SYMBOL_GPL(ethtool_set_ethtool_phy_ops);
...@@ -37,4 +37,6 @@ bool convert_legacy_settings_to_link_ksettings( ...@@ -37,4 +37,6 @@ bool convert_legacy_settings_to_link_ksettings(
int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max); int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max);
int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info); int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
extern const struct ethtool_phy_ops *ethtool_phy_ops;
#endif /* _ETHTOOL_COMMON_H */ #endif /* _ETHTOOL_COMMON_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment