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

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: default avatarPaolo Abeni <pabeni@redhat.com>
parents c749e3f8 186b1da7
Loading
Loading
Loading
Loading
+42 −12
Original line number Diff line number Diff line
@@ -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)
+20 −1
Original line number Diff line number Diff line
@@ -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
	 */
+6 −0
Original line number Diff line number Diff line
@@ -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;