Commit 3eeca4e1 authored by Oleksij Rempel's avatar Oleksij Rempel Committed by Paolo Abeni

net: phy: do not force EEE support

With following patches:
commit 9b01c885 ("net: phy: c22: migrate to genphy_c45_write_eee_adv()")
commit 5827b168 ("net: phy: c45: migrate to genphy_c45_write_eee_adv()")

we set the advertisement to potentially supported values. This behavior
may introduce new regressions on systems where EEE was disabled by
default (BIOS or boot loader configuration or by other ways.)

At same time, with this patches, we would overwrite EEE advertisement
configuration made over ethtool.

To avoid this issues, we need to cache initial and ethtool advertisement
configuration and store it for later use.

Fixes: 9b01c885 ("net: phy: c22: migrate to genphy_c45_write_eee_adv()")
Fixes: 5827b168 ("net: phy: c45: migrate to genphy_c45_write_eee_adv()")
Fixes: 022c3f87 ("net: phy: add genphy_c45_ethtool_get/set_eee() support")
Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent b6478b8c
...@@ -721,8 +721,7 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv) ...@@ -721,8 +721,7 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv)
* @phydev: target phy_device struct * @phydev: target phy_device struct
* @adv: the linkmode advertisement status * @adv: the linkmode advertisement status
*/ */
static int genphy_c45_read_eee_adv(struct phy_device *phydev, int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv)
unsigned long *adv)
{ {
int val; int val;
...@@ -864,7 +863,13 @@ EXPORT_SYMBOL_GPL(genphy_c45_read_eee_abilities); ...@@ -864,7 +863,13 @@ EXPORT_SYMBOL_GPL(genphy_c45_read_eee_abilities);
*/ */
int genphy_c45_an_config_eee_aneg(struct phy_device *phydev) 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); ...@@ -1430,17 +1435,22 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee);
int genphy_c45_ethtool_set_eee(struct phy_device *phydev, int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
struct ethtool_eee *data) struct ethtool_eee *data)
{ {
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {};
int ret; int ret;
if (data->eee_enabled) { if (data->eee_enabled) {
if (data->advertised) if (data->advertised)
adv[0] = data->advertised; ethtool_convert_legacy_u32_to_link_mode(phydev->advertising_eee,
data->advertised);
else 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) if (ret < 0)
return ret; return ret;
if (ret > 0) if (ret > 0)
......
...@@ -3141,6 +3141,25 @@ static int phy_probe(struct device *dev) ...@@ -3141,6 +3141,25 @@ static int phy_probe(struct device *dev)
of_set_phy_supported(phydev); of_set_phy_supported(phydev);
phy_advertise_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 /* Get the EEE modes we want to prohibit. We will ask
* the PHY stop advertising these mode later on * the PHY stop advertising these mode later on
*/ */
......
...@@ -575,6 +575,8 @@ struct macsec_ops; ...@@ -575,6 +575,8 @@ struct macsec_ops;
* @advertising: Currently advertised linkmodes * @advertising: Currently advertised linkmodes
* @adv_old: Saved advertised while power saving for WoL * @adv_old: Saved advertised while power saving for WoL
* @supported_eee: supported PHY EEE linkmodes * @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 * @lp_advertising: Current link partner advertised linkmodes
* @host_interfaces: PHY interface modes supported by host * @host_interfaces: PHY interface modes supported by host
* @eee_broken_modes: Energy efficient ethernet modes which should be prohibited * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited
...@@ -681,6 +683,8 @@ struct phy_device { ...@@ -681,6 +683,8 @@ struct phy_device {
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old);
/* used for eee validation */ /* used for eee validation */
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported_eee); __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. */ /* Host supported PHY interface types. Should be ignored if empty. */
DECLARE_PHY_INTERFACE_MASK(host_interfaces); DECLARE_PHY_INTERFACE_MASK(host_interfaces);
...@@ -1766,6 +1770,7 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, ...@@ -1766,6 +1770,7 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
struct ethtool_eee *data); struct ethtool_eee *data);
int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv); 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_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 */ /* Generic C45 PHY driver */
extern struct phy_driver genphy_c45_driver; extern struct phy_driver genphy_c45_driver;
......
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