diff mbox series

[net-next] net: phylib: do not disable autoneg for fixed speeds >= 1G

Message ID E1sbdxI-0024Eo-HE@rmk-PC.armlinux.org.uk (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [net-next] net: phylib: do not disable autoneg for fixed speeds >= 1G | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 29 this patch: 17
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang fail Errors and warnings before: 53 this patch: 18
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 31 this patch: 17
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 70 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 40 this patch: 40
netdev/source_inline success Was 0 now: 0

Commit Message

Russell King (Oracle) Aug. 7, 2024, 10:31 a.m. UTC
We have an increasing number of drivers that are forcing
auto-negotiation to be enabled for speeds of 1G or faster.

It would appear that auto-negotiation is mandatory for speeds above
100M. In 802.3, Annex 40C's state diagrams seems to imply that
mr_autoneg_enable (BMCR AN ENABLE) doesn't affect whether or not the
AN state machines work for 1000base-T, and some PHY datasheets (e.g.
Marvell Alaska) state that disabling mr_autoneg_enable leaves AN
enabled but forced to 1G full duplex.

Other PHY datasheets imply that BMCR AN ENABLE should not be cleared
for >= 1G.

Thus, this should be handled in phylib rather than in each driver.

Rather than erroring out, arrange to implement the Marvell Alaska
solution but in software for all PHYs: generate an appropriate
single-speed advertisement for the requested speed, and keep AN
enabled to the PHY driver. However, to avoid userspace API breakage,
continue to report to userspace that we have AN disabled.

Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
 drivers/net/phy/phy_device.c | 34 +++++++++++++++++++++++++---------
 1 file changed, 25 insertions(+), 9 deletions(-)

Comments

kernel test robot Aug. 7, 2024, 8:36 p.m. UTC | #1
Hi Russell,

kernel test robot noticed the following build errors:

[auto build test ERROR on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Russell-King-Oracle/net-phylib-do-not-disable-autoneg-for-fixed-speeds-1G/20240807-185909
base:   net-next/main
patch link:    https://lore.kernel.org/r/E1sbdxI-0024Eo-HE%40rmk-PC.armlinux.org.uk
patch subject: [PATCH net-next] net: phylib: do not disable autoneg for fixed speeds >= 1G
config: i386-buildonly-randconfig-004-20240808 (https://download.01.org/0day-ci/archive/20240808/202408080419.a2PXcqh8-lkp@intel.com/config)
compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240808/202408080419.a2PXcqh8-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408080419.a2PXcqh8-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/net/phy/phy_device.c:2124:34: error: passing 'const unsigned long *' to parameter of type 'unsigned long *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
    2124 |         adv = linkmode_adv_to_mii_adv_t(advert);
         |                                         ^~~~~~
   include/linux/mii.h:143:60: note: passing argument to parameter 'advertising' here
     143 | static inline u32 linkmode_adv_to_mii_adv_t(unsigned long *advertising)
         |                                                            ^
   drivers/net/phy/phy_device.c:2147:39: error: passing 'const unsigned long *' to parameter of type 'unsigned long *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
    2147 |         adv = linkmode_adv_to_mii_ctrl1000_t(advert);
         |                                              ^~~~~~
   include/linux/mii.h:218:65: note: passing argument to parameter 'advertising' here
     218 | static inline u32 linkmode_adv_to_mii_ctrl1000_t(unsigned long *advertising)
         |                                                                 ^
>> drivers/net/phy/phy_device.c:2401:4: error: call to undeclared function 'linkmode_set'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    2401 |                         linkmode_set(set->bit, fixed_advert);
         |                         ^
   3 errors generated.


vim +2124 drivers/net/phy/phy_device.c

  2107	
  2108	/**
  2109	 * genphy_config_advert - sanitize and advertise auto-negotiation parameters
  2110	 * @phydev: target phy_device struct
  2111	 * @advert: auto-negotiation parameters to advertise
  2112	 *
  2113	 * Description: Writes MII_ADVERTISE with the appropriate values,
  2114	 *   after sanitizing the values to make sure we only advertise
  2115	 *   what is supported.  Returns < 0 on error, 0 if the PHY's advertisement
  2116	 *   hasn't changed, and > 0 if it has changed.
  2117	 */
  2118	static int genphy_config_advert(struct phy_device *phydev,
  2119					const unsigned long *advert)
  2120	{
  2121		int err, bmsr, changed = 0;
  2122		u32 adv;
  2123	
> 2124		adv = linkmode_adv_to_mii_adv_t(advert);
  2125	
  2126		/* Setup standard advertisement */
  2127		err = phy_modify_changed(phydev, MII_ADVERTISE,
  2128					 ADVERTISE_ALL | ADVERTISE_100BASE4 |
  2129					 ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
  2130					 adv);
  2131		if (err < 0)
  2132			return err;
  2133		if (err > 0)
  2134			changed = 1;
  2135	
  2136		bmsr = phy_read(phydev, MII_BMSR);
  2137		if (bmsr < 0)
  2138			return bmsr;
  2139	
  2140		/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
  2141		 * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
  2142		 * logical 1.
  2143		 */
  2144		if (!(bmsr & BMSR_ESTATEN))
  2145			return changed;
  2146	
  2147		adv = linkmode_adv_to_mii_ctrl1000_t(advert);
  2148	
  2149		err = phy_modify_changed(phydev, MII_CTRL1000,
  2150					 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
  2151					 adv);
  2152		if (err < 0)
  2153			return err;
  2154		if (err > 0)
  2155			changed = 1;
  2156	
  2157		return changed;
  2158	}
  2159
kernel test robot Aug. 7, 2024, 8:46 p.m. UTC | #2
Hi Russell,

kernel test robot noticed the following build errors:

[auto build test ERROR on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Russell-King-Oracle/net-phylib-do-not-disable-autoneg-for-fixed-speeds-1G/20240807-185909
base:   net-next/main
patch link:    https://lore.kernel.org/r/E1sbdxI-0024Eo-HE%40rmk-PC.armlinux.org.uk
patch subject: [PATCH net-next] net: phylib: do not disable autoneg for fixed speeds >= 1G
config: arc-randconfig-001-20240808 (https://download.01.org/0day-ci/archive/20240808/202408080457.vhF74DGf-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240808/202408080457.vhF74DGf-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408080457.vhF74DGf-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   drivers/net/phy/phy_device.c: In function 'genphy_config_advert':
>> drivers/net/phy/phy_device.c:2124:41: warning: passing argument 1 of 'linkmode_adv_to_mii_adv_t' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    2124 |         adv = linkmode_adv_to_mii_adv_t(advert);
         |                                         ^~~~~~
   In file included from include/uapi/linux/mdio.h:15,
                    from include/linux/mdio.h:9,
                    from drivers/net/phy/phy_device.c:23:
   include/linux/mii.h:143:60: note: expected 'long unsigned int *' but argument is of type 'const long unsigned int *'
     143 | static inline u32 linkmode_adv_to_mii_adv_t(unsigned long *advertising)
         |                                             ~~~~~~~~~~~~~~~^~~~~~~~~~~
>> drivers/net/phy/phy_device.c:2147:46: warning: passing argument 1 of 'linkmode_adv_to_mii_ctrl1000_t' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    2147 |         adv = linkmode_adv_to_mii_ctrl1000_t(advert);
         |                                              ^~~~~~
   include/linux/mii.h:218:65: note: expected 'long unsigned int *' but argument is of type 'const long unsigned int *'
     218 | static inline u32 linkmode_adv_to_mii_ctrl1000_t(unsigned long *advertising)
         |                                                  ~~~~~~~~~~~~~~~^~~~~~~~~~~
   drivers/net/phy/phy_device.c: In function '__genphy_config_aneg':
>> drivers/net/phy/phy_device.c:2401:25: error: implicit declaration of function 'linkmode_set'; did you mean 'linkmode_subset'? [-Werror=implicit-function-declaration]
    2401 |                         linkmode_set(set->bit, fixed_advert);
         |                         ^~~~~~~~~~~~
         |                         linkmode_subset
   cc1: some warnings being treated as errors


vim +2401 drivers/net/phy/phy_device.c

  2359	
  2360	/**
  2361	 * __genphy_config_aneg - restart auto-negotiation or write BMCR
  2362	 * @phydev: target phy_device struct
  2363	 * @changed: whether autoneg is requested
  2364	 *
  2365	 * Description: If auto-negotiation is enabled, we configure the
  2366	 *   advertising, and then restart auto-negotiation.  If it is not
  2367	 *   enabled, then we write the BMCR.
  2368	 */
  2369	int __genphy_config_aneg(struct phy_device *phydev, bool changed)
  2370	{
  2371		__ETHTOOL_DECLARE_LINK_MODE_MASK(fixed_advert);
  2372		const struct phy_setting *set;
  2373		unsigned long *advert;
  2374		int err;
  2375	
  2376		err = genphy_c45_an_config_eee_aneg(phydev);
  2377		if (err < 0)
  2378			return err;
  2379		else if (err)
  2380			changed = true;
  2381	
  2382		err = genphy_setup_master_slave(phydev);
  2383		if (err < 0)
  2384			return err;
  2385		else if (err)
  2386			changed = true;
  2387	
  2388		if (phydev->autoneg == AUTONEG_ENABLE) {
  2389			/* Only allow advertising what this PHY supports */
  2390			linkmode_and(phydev->advertising, phydev->advertising,
  2391				     phydev->supported);
  2392			advert = phydev->advertising;
  2393		} else if (phydev->speed < SPEED_1000) {
  2394			return genphy_setup_forced(phydev);
  2395		} else {
  2396			linkmode_zero(fixed_advert);
  2397	
  2398			set = phy_lookup_setting(phydev->speed, phydev->duplex,
  2399						 phydev->supported, true);
  2400			if (set)
> 2401				linkmode_set(set->bit, fixed_advert);
  2402	
  2403			advert = fixed_advert;
  2404		}
  2405	
  2406		err = genphy_config_advert(phydev, advert);
  2407		if (err < 0) /* error */
  2408			return err;
  2409		else if (err)
  2410			changed = true;
  2411	
  2412		return genphy_check_and_restart_aneg(phydev, changed);
  2413	}
  2414	EXPORT_SYMBOL(__genphy_config_aneg);
  2415
diff mbox series

Patch

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 29a4225cb712..76312591dcb8 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2103,22 +2103,20 @@  EXPORT_SYMBOL(phy_reset_after_clk_enable);
 /**
  * genphy_config_advert - sanitize and advertise auto-negotiation parameters
  * @phydev: target phy_device struct
+ * @advert: auto-negotiation parameters to advertise
  *
  * Description: Writes MII_ADVERTISE with the appropriate values,
  *   after sanitizing the values to make sure we only advertise
  *   what is supported.  Returns < 0 on error, 0 if the PHY's advertisement
  *   hasn't changed, and > 0 if it has changed.
  */
-static int genphy_config_advert(struct phy_device *phydev)
+static int genphy_config_advert(struct phy_device *phydev,
+				const unsigned long *advert)
 {
 	int err, bmsr, changed = 0;
 	u32 adv;
 
-	/* Only allow advertising what this PHY supports */
-	linkmode_and(phydev->advertising, phydev->advertising,
-		     phydev->supported);
-
-	adv = linkmode_adv_to_mii_adv_t(phydev->advertising);
+	adv = linkmode_adv_to_mii_adv_t(advert);
 
 	/* Setup standard advertisement */
 	err = phy_modify_changed(phydev, MII_ADVERTISE,
@@ -2141,7 +2139,7 @@  static int genphy_config_advert(struct phy_device *phydev)
 	if (!(bmsr & BMSR_ESTATEN))
 		return changed;
 
-	adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
+	adv = linkmode_adv_to_mii_ctrl1000_t(advert);
 
 	err = phy_modify_changed(phydev, MII_CTRL1000,
 				 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
@@ -2365,6 +2363,9 @@  EXPORT_SYMBOL(genphy_check_and_restart_aneg);
  */
 int __genphy_config_aneg(struct phy_device *phydev, bool changed)
 {
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(fixed_advert);
+	const struct phy_setting *set;
+	unsigned long *advert;
 	int err;
 
 	err = genphy_c45_an_config_eee_aneg(phydev);
@@ -2379,10 +2380,25 @@  int __genphy_config_aneg(struct phy_device *phydev, bool changed)
 	else if (err)
 		changed = true;
 
-	if (AUTONEG_ENABLE != phydev->autoneg)
+	if (phydev->autoneg == AUTONEG_ENABLE) {
+		/* Only allow advertising what this PHY supports */
+		linkmode_and(phydev->advertising, phydev->advertising,
+			     phydev->supported);
+		advert = phydev->advertising;
+	} else if (phydev->speed < SPEED_1000) {
 		return genphy_setup_forced(phydev);
+	} else {
+		linkmode_zero(fixed_advert);
+
+		set = phy_lookup_setting(phydev->speed, phydev->duplex,
+					 phydev->supported, true);
+		if (set)
+			linkmode_set(set->bit, fixed_advert);
+
+		advert = fixed_advert;
+	}
 
-	err = genphy_config_advert(phydev);
+	err = genphy_config_advert(phydev, advert);
 	if (err < 0) /* error */
 		return err;
 	else if (err)