All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC v2 0/2] phylib non-autoneg speed setting
@ 2017-04-06 10:00 Russell King - ARM Linux
  2017-04-06 10:01 ` [PATCH RFC v2 1/2] net: phy: improve phylib correctness for non-autoneg settings Russell King
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Russell King - ARM Linux @ 2017-04-06 10:00 UTC (permalink / raw)
  To: Florian Fainelli, Andrew Lunn; +Cc: David S. Miller, netdev

This set of two patches fixes and cleans up the phylib code associated
with selecting the fixed mode.

phylib currently assumes that all PHYs will support the 10baseT/Half mode
of operation irrespective of the supported bitmask, because of the way
phy_find_valid() and phy_find_setting() operate.

This series resolves that by reimplementing the table lookup, filtering
out all unsupported modes.  This results in an unsupported speed setting
always choosing one of the speeds that are supported by the PHY.  Full
details are in the patch commit log.

The second patch cleans up the loop in phy_supported_speeds().

 drivers/net/phy/phy.c | 119 ++++++++++++++++++++++++++++----------------------
 1 file changed, 68 insertions(+), 51 deletions(-)

v1->v2: fixed 0-day build errors

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH RFC v2 1/2] net: phy: improve phylib correctness for non-autoneg settings
  2017-04-06 10:00 [PATCH RFC v2 0/2] phylib non-autoneg speed setting Russell King - ARM Linux
@ 2017-04-06 10:01 ` Russell King
  2017-04-06 10:01 ` [PATCH RFC v2 2/2] net: phy: simplify phy_supported_speeds() Russell King
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Russell King @ 2017-04-06 10:01 UTC (permalink / raw)
  To: Florian Fainelli, Andrew Lunn; +Cc: David S. Miller, netdev

phylib has some undesirable behaviour when forcing a link mode through
ethtool.  phylib uses this code:

	idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
			features);

to find an index in the settings table.  phy_find_setting() starts at
index 0, and scans upwards looking for an exact speed and duplex match.
When it doesn't find it, it returns MAX_NUM_SETTINGS - 1, which is
10baseT-Half duplex.

phy_find_valid() then scans from the point (and effectively only checks
one entry) before bailing out, returning MAX_NUM_SETTINGS - 1.

phy_sanitize_settings() then sets ->speed to SPEED_10 and ->duplex to
DUPLEX_HALF whether or not 10baseT-Half is supported or not.  This goes
against all the comments against these functions, and 10baseT-Half may
not even be supported by the hardware.

Rework these functions, introducing a new method of scanning the table.
There are two modes of lookup that phylib wants: exact, and inexact.

- in exact mode, we return either an exact match or failure
- in inexact mode, we return an exact match if it exists, a match at
  the highest speed that is not greater than the requested speed
  (ignoring duplex), or failing that, the lowest supported speed, or
  failure.

The biggest difference is that we always check whether the entry is
supported before further consideration, so all unsupported entries are
not considered as candidates.

This results in arguably saner behaviour, better matches the comments,
and is probably what users would expect.

This becomes important as ethernet speeds increase, PHYs exist which do
not support the 10Mbit speeds, and half-duplex is likely to become
obsolete - it's already not even an option on 10Gbit and faster links.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 drivers/net/phy/phy.c | 109 ++++++++++++++++++++++++++++++--------------------
 1 file changed, 66 insertions(+), 43 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 6811d1ef4ef2..b50b6e61aace 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -176,7 +176,9 @@ struct phy_setting {
 	u32 setting;
 };
 
-/* A mapping of all SUPPORTED settings to speed/duplex */
+/* A mapping of all SUPPORTED settings to speed/duplex.  This table
+ * must be grouped by speed and sorted in descending match priority
+ * - iow, descending speed. */
 static const struct phy_setting settings[] = {
 	{
 		.speed = SPEED_10000,
@@ -235,45 +237,70 @@ static const struct phy_setting settings[] = {
 	},
 };
 
-#define MAX_NUM_SETTINGS ARRAY_SIZE(settings)
-
 /**
- * phy_find_setting - find a PHY settings array entry that matches speed & duplex
+ * phy_lookup_setting - lookup a PHY setting
  * @speed: speed to match
  * @duplex: duplex to match
+ * @feature: allowed link modes
+ * @exact: an exact match is required
+ *
+ * Search the settings array for a setting that matches the speed and
+ * duplex, and which is supported.
+ *
+ * If @exact is unset, either an exact match or %NULL for no match will
+ * be returned.
  *
- * Description: Searches the settings array for the setting which
- *   matches the desired speed and duplex, and returns the index
- *   of that setting.  Returns the index of the last setting if
- *   none of the others match.
+ * If @exact is set, an exact match, the fastest supported setting at
+ * or below the specified speed, the slowest supported setting, or if
+ * they all fail, %NULL will be returned.
  */
-static inline unsigned int phy_find_setting(int speed, int duplex)
+static const struct phy_setting *
+phy_lookup_setting(int speed, int duplex, u32 features, bool exact)
 {
-	unsigned int idx = 0;
+	const struct phy_setting *p, *match = NULL, *last = NULL;
+	int i;
+
+	for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
+		if (p->setting & features) {
+			last = p;
+			if (p->speed == speed && p->duplex == duplex) {
+				/* Exact match for speed and duplex */
+				match = p;
+				break;
+			} else if (!exact) {
+				if (!match && p->speed <= speed)
+					/* Candidate */
+					match = p;
+
+				if (p->speed < speed)
+					break;
+			}
+		}
+	}
 
-	while (idx < ARRAY_SIZE(settings) &&
-	       (settings[idx].speed != speed || settings[idx].duplex != duplex))
-		idx++;
+	if (!match && !exact)
+		match = last;
 
-	return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
+	return match;
 }
 
 /**
- * phy_find_valid - find a PHY setting that matches the requested features mask
- * @idx: The first index in settings[] to search
- * @features: A mask of the valid settings
+ * phy_find_valid - find a PHY setting that matches the requested parameters
+ * @speed: desired speed
+ * @duplex: desired duplex
+ * @supported: mask of supported link modes
  *
- * Description: Returns the index of the first valid setting less
- *   than or equal to the one pointed to by idx, as determined by
- *   the mask in features.  Returns the index of the last setting
- *   if nothing else matches.
+ * Locate a supported phy setting that is, in priority order:
+ * - an exact match for the specified speed and duplex mode
+ * - a match for the specified speed, or slower speed
+ * - the slowest supported speed
+ * Returns the matched phy_setting entry, or %NULL if no supported phy
+ * settings were found.
  */
-static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
+static const struct phy_setting *
+phy_find_valid(int speed, int duplex, u32 supported)
 {
-	while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
-		idx++;
-
-	return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
+	return phy_lookup_setting(speed, duplex, supported, false);
 }
 
 /**
@@ -293,11 +320,9 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
 	unsigned int count = 0;
 	unsigned int idx = 0;
 
-	while (idx < MAX_NUM_SETTINGS && count < size) {
-		idx = phy_find_valid(idx, phy->supported);
-
+	for (idx = 0; idx < ARRAY_SIZE(settings) && count < size; idx++) {
 		if (!(settings[idx].setting & phy->supported))
-			break;
+			continue;
 
 		/* Assumes settings are grouped by speed */
 		if ((count == 0) ||
@@ -305,7 +330,6 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
 			speeds[count] = settings[idx].speed;
 			count++;
 		}
-		idx++;
 	}
 
 	return count;
@@ -322,12 +346,7 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
  */
 static inline bool phy_check_valid(int speed, int duplex, u32 features)
 {
-	unsigned int idx;
-
-	idx = phy_find_valid(phy_find_setting(speed, duplex), features);
-
-	return settings[idx].speed == speed && settings[idx].duplex == duplex &&
-		(settings[idx].setting & features);
+	return !!phy_lookup_setting(speed, duplex, features, true);
 }
 
 /**
@@ -340,18 +359,22 @@ static inline bool phy_check_valid(int speed, int duplex, u32 features)
  */
 static void phy_sanitize_settings(struct phy_device *phydev)
 {
+	const struct phy_setting *setting;
 	u32 features = phydev->supported;
-	unsigned int idx;
 
 	/* Sanitize settings based on PHY capabilities */
 	if ((features & SUPPORTED_Autoneg) == 0)
 		phydev->autoneg = AUTONEG_DISABLE;
 
-	idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
-			features);
-
-	phydev->speed = settings[idx].speed;
-	phydev->duplex = settings[idx].duplex;
+	setting = phy_find_valid(phydev->speed, phydev->duplex, features);
+	if (setting) {
+		phydev->speed = setting->speed;
+		phydev->duplex = setting->duplex;
+	} else {
+		/* We failed to find anything (no supported speeds?) */
+		phydev->speed = SPEED_UNKNOWN;
+		phydev->duplex = DUPLEX_UNKNOWN;
+	}
 }
 
 /**
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH RFC v2 2/2] net: phy: simplify phy_supported_speeds()
  2017-04-06 10:00 [PATCH RFC v2 0/2] phylib non-autoneg speed setting Russell King - ARM Linux
  2017-04-06 10:01 ` [PATCH RFC v2 1/2] net: phy: improve phylib correctness for non-autoneg settings Russell King
@ 2017-04-06 10:01 ` Russell King
  2017-04-07 20:51 ` [PATCH RFC v2 0/2] phylib non-autoneg speed setting Florian Fainelli
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Russell King @ 2017-04-06 10:01 UTC (permalink / raw)
  To: Florian Fainelli, Andrew Lunn; +Cc: David S. Miller, netdev

Simplify the loop in phy_supported_speeds().

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 drivers/net/phy/phy.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index b50b6e61aace..f3015e6a52ab 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -320,17 +320,11 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
 	unsigned int count = 0;
 	unsigned int idx = 0;
 
-	for (idx = 0; idx < ARRAY_SIZE(settings) && count < size; idx++) {
-		if (!(settings[idx].setting & phy->supported))
-			continue;
-
+	for (idx = 0; idx < ARRAY_SIZE(settings) && count < size; idx++)
 		/* Assumes settings are grouped by speed */
-		if ((count == 0) ||
-		    (speeds[count - 1] != settings[idx].speed)) {
-			speeds[count] = settings[idx].speed;
-			count++;
-		}
-	}
+		if ((settings[idx].setting & phy->supported) &&
+		    (count == 0 || speeds[count - 1] != settings[idx].speed))
+			speeds[count++] = settings[idx].speed;
 
 	return count;
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH RFC v2 0/2] phylib non-autoneg speed setting
  2017-04-06 10:00 [PATCH RFC v2 0/2] phylib non-autoneg speed setting Russell King - ARM Linux
  2017-04-06 10:01 ` [PATCH RFC v2 1/2] net: phy: improve phylib correctness for non-autoneg settings Russell King
  2017-04-06 10:01 ` [PATCH RFC v2 2/2] net: phy: simplify phy_supported_speeds() Russell King
@ 2017-04-07 20:51 ` Florian Fainelli
  2017-04-13 15:49 ` [PATCH 1/2] net: phy: improve phylib correctness for non-autoneg settings Russell King
  2017-04-13 15:49 ` [PATCH 2/2] net: phy: simplify phy_supported_speeds() Russell King
  4 siblings, 0 replies; 8+ messages in thread
From: Florian Fainelli @ 2017-04-07 20:51 UTC (permalink / raw)
  To: Russell King - ARM Linux, Andrew Lunn; +Cc: David S. Miller, netdev



On 04/06/2017 03:00 AM, Russell King - ARM Linux wrote:
> This set of two patches fixes and cleans up the phylib code associated
> with selecting the fixed mode.
> 
> phylib currently assumes that all PHYs will support the 10baseT/Half mode
> of operation irrespective of the supported bitmask, because of the way
> phy_find_valid() and phy_find_setting() operate.
> 
> This series resolves that by reimplementing the table lookup, filtering
> out all unsupported modes.  This results in an unsupported speed setting
> always choosing one of the speeds that are supported by the PHY.  Full
> details are in the patch commit log.
> 
> The second patch cleans up the loop in phy_supported_speeds().

This looks totally fine to me, do you mind resubmitting as non RFC?

> 
>  drivers/net/phy/phy.c | 119 ++++++++++++++++++++++++++++----------------------
>  1 file changed, 68 insertions(+), 51 deletions(-)
> 
> v1->v2: fixed 0-day build errors
> 

-- 
Florian

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] net: phy: improve phylib correctness for non-autoneg settings
  2017-04-06 10:00 [PATCH RFC v2 0/2] phylib non-autoneg speed setting Russell King - ARM Linux
                   ` (2 preceding siblings ...)
  2017-04-07 20:51 ` [PATCH RFC v2 0/2] phylib non-autoneg speed setting Florian Fainelli
@ 2017-04-13 15:49 ` Russell King
  2017-04-17 17:25   ` David Miller
  2017-04-13 15:49 ` [PATCH 2/2] net: phy: simplify phy_supported_speeds() Russell King
  4 siblings, 1 reply; 8+ messages in thread
From: Russell King @ 2017-04-13 15:49 UTC (permalink / raw)
  To: Florian Fainelli, Andrew Lunn; +Cc: David S. Miller, netdev

phylib has some undesirable behaviour when forcing a link mode through
ethtool.  phylib uses this code:

	idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
			features);

to find an index in the settings table.  phy_find_setting() starts at
index 0, and scans upwards looking for an exact speed and duplex match.
When it doesn't find it, it returns MAX_NUM_SETTINGS - 1, which is
10baseT-Half duplex.

phy_find_valid() then scans from the point (and effectively only checks
one entry) before bailing out, returning MAX_NUM_SETTINGS - 1.

phy_sanitize_settings() then sets ->speed to SPEED_10 and ->duplex to
DUPLEX_HALF whether or not 10baseT-Half is supported or not.  This goes
against all the comments against these functions, and 10baseT-Half may
not even be supported by the hardware.

Rework these functions, introducing a new method of scanning the table.
There are two modes of lookup that phylib wants: exact, and inexact.

- in exact mode, we return either an exact match or failure
- in inexact mode, we return an exact match if it exists, a match at
  the highest speed that is not greater than the requested speed
  (ignoring duplex), or failing that, the lowest supported speed, or
  failure.

The biggest difference is that we always check whether the entry is
supported before further consideration, so all unsupported entries are
not considered as candidates.

This results in arguably saner behaviour, better matches the comments,
and is probably what users would expect.

This becomes important as ethernet speeds increase, PHYs exist which do
not support the 10Mbit speeds, and half-duplex is likely to become
obsolete - it's already not even an option on 10Gbit and faster links.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 drivers/net/phy/phy.c | 109 ++++++++++++++++++++++++++++++--------------------
 1 file changed, 66 insertions(+), 43 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index bf7d614ff18f..00280d4eeb56 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -176,7 +176,9 @@ struct phy_setting {
 	u32 setting;
 };
 
-/* A mapping of all SUPPORTED settings to speed/duplex */
+/* A mapping of all SUPPORTED settings to speed/duplex.  This table
+ * must be grouped by speed and sorted in descending match priority
+ * - iow, descending speed. */
 static const struct phy_setting settings[] = {
 	{
 		.speed = SPEED_10000,
@@ -235,45 +237,70 @@ static const struct phy_setting settings[] = {
 	},
 };
 
-#define MAX_NUM_SETTINGS ARRAY_SIZE(settings)
-
 /**
- * phy_find_setting - find a PHY settings array entry that matches speed & duplex
+ * phy_lookup_setting - lookup a PHY setting
  * @speed: speed to match
  * @duplex: duplex to match
+ * @feature: allowed link modes
+ * @exact: an exact match is required
+ *
+ * Search the settings array for a setting that matches the speed and
+ * duplex, and which is supported.
+ *
+ * If @exact is unset, either an exact match or %NULL for no match will
+ * be returned.
  *
- * Description: Searches the settings array for the setting which
- *   matches the desired speed and duplex, and returns the index
- *   of that setting.  Returns the index of the last setting if
- *   none of the others match.
+ * If @exact is set, an exact match, the fastest supported setting at
+ * or below the specified speed, the slowest supported setting, or if
+ * they all fail, %NULL will be returned.
  */
-static inline unsigned int phy_find_setting(int speed, int duplex)
+static const struct phy_setting *
+phy_lookup_setting(int speed, int duplex, u32 features, bool exact)
 {
-	unsigned int idx = 0;
+	const struct phy_setting *p, *match = NULL, *last = NULL;
+	int i;
+
+	for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
+		if (p->setting & features) {
+			last = p;
+			if (p->speed == speed && p->duplex == duplex) {
+				/* Exact match for speed and duplex */
+				match = p;
+				break;
+			} else if (!exact) {
+				if (!match && p->speed <= speed)
+					/* Candidate */
+					match = p;
+
+				if (p->speed < speed)
+					break;
+			}
+		}
+	}
 
-	while (idx < ARRAY_SIZE(settings) &&
-	       (settings[idx].speed != speed || settings[idx].duplex != duplex))
-		idx++;
+	if (!match && !exact)
+		match = last;
 
-	return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
+	return match;
 }
 
 /**
- * phy_find_valid - find a PHY setting that matches the requested features mask
- * @idx: The first index in settings[] to search
- * @features: A mask of the valid settings
+ * phy_find_valid - find a PHY setting that matches the requested parameters
+ * @speed: desired speed
+ * @duplex: desired duplex
+ * @supported: mask of supported link modes
  *
- * Description: Returns the index of the first valid setting less
- *   than or equal to the one pointed to by idx, as determined by
- *   the mask in features.  Returns the index of the last setting
- *   if nothing else matches.
+ * Locate a supported phy setting that is, in priority order:
+ * - an exact match for the specified speed and duplex mode
+ * - a match for the specified speed, or slower speed
+ * - the slowest supported speed
+ * Returns the matched phy_setting entry, or %NULL if no supported phy
+ * settings were found.
  */
-static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
+static const struct phy_setting *
+phy_find_valid(int speed, int duplex, u32 supported)
 {
-	while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
-		idx++;
-
-	return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
+	return phy_lookup_setting(speed, duplex, supported, false);
 }
 
 /**
@@ -293,11 +320,9 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
 	unsigned int count = 0;
 	unsigned int idx = 0;
 
-	while (idx < MAX_NUM_SETTINGS && count < size) {
-		idx = phy_find_valid(idx, phy->supported);
-
+	for (idx = 0; idx < ARRAY_SIZE(settings) && count < size; idx++) {
 		if (!(settings[idx].setting & phy->supported))
-			break;
+			continue;
 
 		/* Assumes settings are grouped by speed */
 		if ((count == 0) ||
@@ -305,7 +330,6 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
 			speeds[count] = settings[idx].speed;
 			count++;
 		}
-		idx++;
 	}
 
 	return count;
@@ -322,12 +346,7 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
  */
 static inline bool phy_check_valid(int speed, int duplex, u32 features)
 {
-	unsigned int idx;
-
-	idx = phy_find_valid(phy_find_setting(speed, duplex), features);
-
-	return settings[idx].speed == speed && settings[idx].duplex == duplex &&
-		(settings[idx].setting & features);
+	return !!phy_lookup_setting(speed, duplex, features, true);
 }
 
 /**
@@ -340,18 +359,22 @@ static inline bool phy_check_valid(int speed, int duplex, u32 features)
  */
 static void phy_sanitize_settings(struct phy_device *phydev)
 {
+	const struct phy_setting *setting;
 	u32 features = phydev->supported;
-	unsigned int idx;
 
 	/* Sanitize settings based on PHY capabilities */
 	if ((features & SUPPORTED_Autoneg) == 0)
 		phydev->autoneg = AUTONEG_DISABLE;
 
-	idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
-			features);
-
-	phydev->speed = settings[idx].speed;
-	phydev->duplex = settings[idx].duplex;
+	setting = phy_find_valid(phydev->speed, phydev->duplex, features);
+	if (setting) {
+		phydev->speed = setting->speed;
+		phydev->duplex = setting->duplex;
+	} else {
+		/* We failed to find anything (no supported speeds?) */
+		phydev->speed = SPEED_UNKNOWN;
+		phydev->duplex = DUPLEX_UNKNOWN;
+	}
 }
 
 /**
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] net: phy: simplify phy_supported_speeds()
  2017-04-06 10:00 [PATCH RFC v2 0/2] phylib non-autoneg speed setting Russell King - ARM Linux
                   ` (3 preceding siblings ...)
  2017-04-13 15:49 ` [PATCH 1/2] net: phy: improve phylib correctness for non-autoneg settings Russell King
@ 2017-04-13 15:49 ` Russell King
  2017-04-17 17:25   ` David Miller
  4 siblings, 1 reply; 8+ messages in thread
From: Russell King @ 2017-04-13 15:49 UTC (permalink / raw)
  To: Florian Fainelli, Andrew Lunn; +Cc: David S. Miller, netdev

Simplify the loop in phy_supported_speeds().

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 drivers/net/phy/phy.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 00280d4eeb56..6afbd973a779 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -320,17 +320,11 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
 	unsigned int count = 0;
 	unsigned int idx = 0;
 
-	for (idx = 0; idx < ARRAY_SIZE(settings) && count < size; idx++) {
-		if (!(settings[idx].setting & phy->supported))
-			continue;
-
+	for (idx = 0; idx < ARRAY_SIZE(settings) && count < size; idx++)
 		/* Assumes settings are grouped by speed */
-		if ((count == 0) ||
-		    (speeds[count - 1] != settings[idx].speed)) {
-			speeds[count] = settings[idx].speed;
-			count++;
-		}
-	}
+		if ((settings[idx].setting & phy->supported) &&
+		    (count == 0 || speeds[count - 1] != settings[idx].speed))
+			speeds[count++] = settings[idx].speed;
 
 	return count;
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] net: phy: improve phylib correctness for non-autoneg settings
  2017-04-13 15:49 ` [PATCH 1/2] net: phy: improve phylib correctness for non-autoneg settings Russell King
@ 2017-04-17 17:25   ` David Miller
  0 siblings, 0 replies; 8+ messages in thread
From: David Miller @ 2017-04-17 17:25 UTC (permalink / raw)
  To: rmk+kernel; +Cc: f.fainelli, andrew, netdev

From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Thu, 13 Apr 2017 16:49:15 +0100

> phylib has some undesirable behaviour when forcing a link mode through
> ethtool.  phylib uses this code:
> 
> 	idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
> 			features);
> 
> to find an index in the settings table.  phy_find_setting() starts at
> index 0, and scans upwards looking for an exact speed and duplex match.
> When it doesn't find it, it returns MAX_NUM_SETTINGS - 1, which is
> 10baseT-Half duplex.
> 
> phy_find_valid() then scans from the point (and effectively only checks
> one entry) before bailing out, returning MAX_NUM_SETTINGS - 1.
> 
> phy_sanitize_settings() then sets ->speed to SPEED_10 and ->duplex to
> DUPLEX_HALF whether or not 10baseT-Half is supported or not.  This goes
> against all the comments against these functions, and 10baseT-Half may
> not even be supported by the hardware.
> 
> Rework these functions, introducing a new method of scanning the table.
> There are two modes of lookup that phylib wants: exact, and inexact.
> 
> - in exact mode, we return either an exact match or failure
> - in inexact mode, we return an exact match if it exists, a match at
>   the highest speed that is not greater than the requested speed
>   (ignoring duplex), or failing that, the lowest supported speed, or
>   failure.
> 
> The biggest difference is that we always check whether the entry is
> supported before further consideration, so all unsupported entries are
> not considered as candidates.
> 
> This results in arguably saner behaviour, better matches the comments,
> and is probably what users would expect.
> 
> This becomes important as ethernet speeds increase, PHYs exist which do
> not support the 10Mbit speeds, and half-duplex is likely to become
> obsolete - it's already not even an option on 10Gbit and faster links.
> 
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

Applied to net-next

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] net: phy: simplify phy_supported_speeds()
  2017-04-13 15:49 ` [PATCH 2/2] net: phy: simplify phy_supported_speeds() Russell King
@ 2017-04-17 17:25   ` David Miller
  0 siblings, 0 replies; 8+ messages in thread
From: David Miller @ 2017-04-17 17:25 UTC (permalink / raw)
  To: rmk+kernel; +Cc: f.fainelli, andrew, netdev

From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Thu, 13 Apr 2017 16:49:20 +0100

> Simplify the loop in phy_supported_speeds().
> 
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

Also applied to net-next, thanks.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-04-17 17:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-06 10:00 [PATCH RFC v2 0/2] phylib non-autoneg speed setting Russell King - ARM Linux
2017-04-06 10:01 ` [PATCH RFC v2 1/2] net: phy: improve phylib correctness for non-autoneg settings Russell King
2017-04-06 10:01 ` [PATCH RFC v2 2/2] net: phy: simplify phy_supported_speeds() Russell King
2017-04-07 20:51 ` [PATCH RFC v2 0/2] phylib non-autoneg speed setting Florian Fainelli
2017-04-13 15:49 ` [PATCH 1/2] net: phy: improve phylib correctness for non-autoneg settings Russell King
2017-04-17 17:25   ` David Miller
2017-04-13 15:49 ` [PATCH 2/2] net: phy: simplify phy_supported_speeds() Russell King
2017-04-17 17:25   ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.