summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/phy/phy-c45.c24
-rw-r--r--drivers/net/phy/phy_device.c19
-rw-r--r--include/linux/phy.h5
3 files changed, 41 insertions, 7 deletions
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index 784868e818a7..8717c122e2f3 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -721,8 +721,7 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv)
* @phydev: target phy_device struct
* @adv: the linkmode advertisement status
*/
-static int genphy_c45_read_eee_adv(struct phy_device *phydev,
- unsigned long *adv)
+int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv)
{
int val;
@@ -864,7 +863,13 @@ EXPORT_SYMBOL_GPL(genphy_c45_read_eee_abilities);
*/
int genphy_c45_an_config_eee_aneg(struct phy_device *phydev)
{
- return genphy_c45_write_eee_adv(phydev, phydev->supported_eee);
+ if (!phydev->eee_enabled) {
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {};
+
+ return genphy_c45_write_eee_adv(phydev, adv);
+ }
+
+ return genphy_c45_write_eee_adv(phydev, phydev->advertising_eee);
}
/**
@@ -1430,17 +1435,22 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee);
int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
struct ethtool_eee *data)
{
- __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {};
int ret;
if (data->eee_enabled) {
if (data->advertised)
- adv[0] = data->advertised;
+ ethtool_convert_legacy_u32_to_link_mode(phydev->advertising_eee,
+ data->advertised);
else
- linkmode_copy(adv, phydev->supported_eee);
+ linkmode_copy(phydev->advertising_eee,
+ phydev->supported_eee);
+
+ phydev->eee_enabled = true;
+ } else {
+ phydev->eee_enabled = false;
}
- ret = genphy_c45_write_eee_adv(phydev, adv);
+ ret = genphy_c45_an_config_eee_aneg(phydev);
if (ret < 0)
return ret;
if (ret > 0)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 570a5803f9c2..3f8a64fb9d71 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3141,6 +3141,25 @@ static int phy_probe(struct device *dev)
of_set_phy_supported(phydev);
phy_advertise_supported(phydev);
+ /* Get PHY default EEE advertising modes and handle them as potentially
+ * safe initial configuration.
+ */
+ err = genphy_c45_read_eee_adv(phydev, phydev->advertising_eee);
+ if (err)
+ return err;
+
+ /* There is no "enabled" flag. If PHY is advertising, assume it is
+ * kind of enabled.
+ */
+ phydev->eee_enabled = !linkmode_empty(phydev->advertising_eee);
+
+ /* Some PHYs may advertise, by default, not support EEE modes. So,
+ * we need to clean them.
+ */
+ if (phydev->eee_enabled)
+ linkmode_and(phydev->advertising_eee, phydev->supported_eee,
+ phydev->advertising_eee);
+
/* Get the EEE modes we want to prohibit. We will ask
* the PHY stop advertising these mode later on
*/
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 19d83e112beb..36bf0bbc8efa 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -575,6 +575,8 @@ struct macsec_ops;
* @advertising: Currently advertised linkmodes
* @adv_old: Saved advertised while power saving for WoL
* @supported_eee: supported PHY EEE linkmodes
+ * @advertising_eee: Currently advertised EEE linkmodes
+ * @eee_enabled: Flag indicating whether the EEE feature is enabled
* @lp_advertising: Current link partner advertised linkmodes
* @host_interfaces: PHY interface modes supported by host
* @eee_broken_modes: Energy efficient ethernet modes which should be prohibited
@@ -681,6 +683,8 @@ struct phy_device {
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old);
/* used for eee validation */
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported_eee);
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising_eee);
+ bool eee_enabled;
/* Host supported PHY interface types. Should be ignored if empty. */
DECLARE_PHY_INTERFACE_MASK(host_interfaces);
@@ -1766,6 +1770,7 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
struct ethtool_eee *data);
int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv);
int genphy_c45_an_config_eee_aneg(struct phy_device *phydev);
+int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv);
/* Generic C45 PHY driver */
extern struct phy_driver genphy_c45_driver;