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.de
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2023-02-23 13:43:26 +01:00
commit 1e30373ea5
3 changed files with 68 additions and 13 deletions

View File

@ -262,7 +262,7 @@ int genphy_c45_an_config_aneg(struct phy_device *phydev)
linkmode_and(phydev->advertising, phydev->advertising,
phydev->supported);
ret = genphy_c45_write_eee_adv(phydev, phydev->supported_eee);
ret = genphy_c45_an_config_eee_aneg(phydev);
if (ret < 0)
return ret;
else if (ret)
@ -674,7 +674,7 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv)
{
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);
/* 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)
* @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;
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
* (Register 7.60)
*/
@ -762,7 +761,7 @@ static int genphy_c45_read_eee_lpa(struct phy_device *phydev,
{
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
* (Register 7.61)
*/
@ -858,6 +857,21 @@ int genphy_c45_read_eee_abilities(struct phy_device *phydev)
}
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
* @phydev: target phy_device struct
@ -1421,17 +1435,33 @@ 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;
else
linkmode_copy(adv, phydev->supported_eee);
if (data->advertised) {
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv);
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)
return ret;
if (ret > 0)

View File

@ -2231,7 +2231,7 @@ int __genphy_config_aneg(struct phy_device *phydev, bool changed)
{
int err;
err = genphy_c45_write_eee_adv(phydev, phydev->supported_eee);
err = genphy_c45_an_config_eee_aneg(phydev);
if (err < 0)
return err;
else if (err)
@ -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
*/

View File

@ -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);
@ -1765,6 +1769,8 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev,
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;