diff --git a/net/ethtool/common.c b/net/ethtool/common.c index 5fb19050991e06..267fd3600f15a7 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -661,6 +661,44 @@ int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index) } EXPORT_SYMBOL(ethtool_get_phc_vclocks); +int __ethtool_get_eee(struct net_device *dev, struct ethtool_eee *eee) +{ + const struct ethtool_ops *ops = dev->ethtool_ops; + struct phy_device *phydev = dev->phydev; + int ret; + + if (ops->get_eee) + ret = ops->get_eee(dev, eee); + else + ret = -EOPNOTSUPP; + + if (ret == -EOPNOTSUPP) { + if (phydev && phydev->is_smart_eee_phy) + ret = phy_ethtool_get_eee(phydev, eee); + } + + return ret; +} + +int __ethtool_set_eee(struct net_device *dev, struct ethtool_eee *eee) +{ + const struct ethtool_ops *ops = dev->ethtool_ops; + struct phy_device *phydev = dev->phydev; + int ret; + + if (ops->set_eee) + ret = ops->set_eee(dev, eee); + else + ret = -EOPNOTSUPP; + + if (ret == -EOPNOTSUPP) { + if (phydev && phydev->is_smart_eee_phy) + ret = phy_ethtool_set_eee(phydev, eee); + } + + return ret; +} + const struct ethtool_phy_ops *ethtool_phy_ops; void ethtool_set_ethtool_phy_ops(const struct ethtool_phy_ops *ops) diff --git a/net/ethtool/common.h b/net/ethtool/common.h index 28b8aaaf9bcb3c..59c1906ec800b9 100644 --- a/net/ethtool/common.h +++ b/net/ethtool/common.h @@ -45,6 +45,8 @@ bool convert_legacy_settings_to_link_ksettings( int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max); int ethtool_get_max_rxnfc_channel(struct net_device *dev, u64 *max); int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info); +int __ethtool_get_eee(struct net_device *dev, struct ethtool_eee *eee); +int __ethtool_set_eee(struct net_device *dev, struct ethtool_eee *eee); extern const struct ethtool_phy_ops *ethtool_phy_ops; extern const struct ethtool_pse_ops *ethtool_pse_ops; diff --git a/net/ethtool/eee.c b/net/ethtool/eee.c index 42104bcb0e47b1..43b8661842972c 100644 --- a/net/ethtool/eee.c +++ b/net/ethtool/eee.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only +#include + #include "netlink.h" #include "common.h" #include "bitset.h" @@ -32,12 +34,10 @@ static int eee_prepare_data(const struct ethnl_req_info *req_base, struct net_device *dev = reply_base->dev; int ret; - if (!dev->ethtool_ops->get_eee) - return -EOPNOTSUPP; ret = ethnl_ops_begin(dev); if (ret < 0) return ret; - ret = dev->ethtool_ops->get_eee(dev, &data->eee); + ret = __ethtool_get_eee(dev, &data->eee); ethnl_ops_complete(dev); return ret; @@ -123,8 +123,13 @@ static int ethnl_set_eee_validate(struct ethnl_req_info *req_info, struct genl_info *info) { const struct ethtool_ops *ops = req_info->dev->ethtool_ops; + struct net_device *dev = req_info->dev; + + if ((ops->get_eee && ops->set_eee) || + (dev->phydev && dev->phydev->is_smart_eee_phy)) + return 1; - return ops->get_eee && ops->set_eee ? 1 : -EOPNOTSUPP; + return -EOPNOTSUPP; } static int @@ -136,7 +141,7 @@ ethnl_set_eee(struct ethnl_req_info *req_info, struct genl_info *info) bool mod = false; int ret; - ret = dev->ethtool_ops->get_eee(dev, &eee); + ret = __ethtool_get_eee(dev, &eee); if (ret < 0) return ret; @@ -153,7 +158,7 @@ ethnl_set_eee(struct ethnl_req_info *req_info, struct genl_info *info) if (!mod) return 0; - ret = dev->ethtool_ops->set_eee(dev, &eee); + ret = __ethtool_set_eee(dev, &eee); return ret < 0 ? ret : 1; }