Commit 1e30373e authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'net-phy-eee-fixes'

Oleksij Rempel says:

====================
net: phy: EEE fixes

changes v3:
- add kernel test robot tags to commit log
- reword comment for genphy_c45_an_config_eee_aneg() function

changes v2:
- restore previous ethtool set logic for the case where advertisements
  are not provided by user space.
- use ethtool_convert_legacy_u32_to_link_mode() where possible
- genphy_c45_an_config_eee_aneg(): move adv initialization in to the if
  scope.

Different EEE related fixes.
====================

Link: https://lore.kernel.org/r/20230222055043.113711-1-o.rempel@pengutronix.deSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents c749e3f8 186b1da7
...@@ -262,7 +262,7 @@ int genphy_c45_an_config_aneg(struct phy_device *phydev) ...@@ -262,7 +262,7 @@ int genphy_c45_an_config_aneg(struct phy_device *phydev)
linkmode_and(phydev->advertising, phydev->advertising, linkmode_and(phydev->advertising, phydev->advertising,
phydev->supported); phydev->supported);
ret = genphy_c45_write_eee_adv(phydev, phydev->supported_eee); ret = genphy_c45_an_config_eee_aneg(phydev);
if (ret < 0) if (ret < 0)
return ret; return ret;
else if (ret) else if (ret)
...@@ -674,7 +674,7 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv) ...@@ -674,7 +674,7 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv)
{ {
int val, changed; int val, changed;
if (linkmode_intersects(phydev->supported, PHY_EEE_CAP1_FEATURES)) { if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
val = linkmode_to_mii_eee_cap1_t(adv); val = linkmode_to_mii_eee_cap1_t(adv);
/* In eee_broken_modes are stored MDIO_AN_EEE_ADV specific raw /* In eee_broken_modes are stored MDIO_AN_EEE_ADV specific raw
...@@ -721,12 +721,11 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv) ...@@ -721,12 +721,11 @@ 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;
if (linkmode_intersects(phydev->supported, PHY_EEE_CAP1_FEATURES)) { if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
/* IEEE 802.3-2018 45.2.7.13 EEE advertisement 1 /* IEEE 802.3-2018 45.2.7.13 EEE advertisement 1
* (Register 7.60) * (Register 7.60)
*/ */
...@@ -762,7 +761,7 @@ static int genphy_c45_read_eee_lpa(struct phy_device *phydev, ...@@ -762,7 +761,7 @@ static int genphy_c45_read_eee_lpa(struct phy_device *phydev,
{ {
int val; int val;
if (linkmode_intersects(phydev->supported, PHY_EEE_CAP1_FEATURES)) { if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
/* IEEE 802.3-2018 45.2.7.14 EEE link partner ability 1 /* IEEE 802.3-2018 45.2.7.14 EEE link partner ability 1
* (Register 7.61) * (Register 7.61)
*/ */
...@@ -858,6 +857,21 @@ int genphy_c45_read_eee_abilities(struct phy_device *phydev) ...@@ -858,6 +857,21 @@ int genphy_c45_read_eee_abilities(struct phy_device *phydev)
} }
EXPORT_SYMBOL_GPL(genphy_c45_read_eee_abilities); EXPORT_SYMBOL_GPL(genphy_c45_read_eee_abilities);
/**
* genphy_c45_an_config_eee_aneg - configure EEE advertisement
* @phydev: target phy_device struct
*/
int genphy_c45_an_config_eee_aneg(struct phy_device *phydev)
{
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);
}
/** /**
* genphy_c45_pma_read_abilities - read supported link modes from PMA * genphy_c45_pma_read_abilities - read supported link modes from PMA
* @phydev: target phy_device struct * @phydev: target phy_device struct
...@@ -1421,17 +1435,33 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee); ...@@ -1421,17 +1435,33 @@ 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_DECLARE_LINK_MODE_MASK(adv);
else
linkmode_copy(adv, phydev->supported_eee); ethtool_convert_legacy_u32_to_link_mode(adv,
data->advertised);
linkmode_andnot(adv, adv, phydev->supported_eee);
if (!linkmode_empty(adv)) {
phydev_warn(phydev, "At least some EEE link modes are not supported.\n");
return -EINVAL;
}
ethtool_convert_legacy_u32_to_link_mode(phydev->advertising_eee,
data->advertised);
} else {
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)
......
...@@ -2231,7 +2231,7 @@ int __genphy_config_aneg(struct phy_device *phydev, bool changed) ...@@ -2231,7 +2231,7 @@ int __genphy_config_aneg(struct phy_device *phydev, bool changed)
{ {
int err; int err;
err = genphy_c45_write_eee_adv(phydev, phydev->supported_eee); err = genphy_c45_an_config_eee_aneg(phydev);
if (err < 0) if (err < 0)
return err; return err;
else if (err) else if (err)
...@@ -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);
...@@ -1765,6 +1769,8 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev, ...@@ -1765,6 +1769,8 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev,
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);
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_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