Skip to content

Commit fc81e25

Browse files
minimaxwellPaolo Abeni
authored andcommitted
net: phy: phy_caps: Allow looking-up link caps based on speed and duplex
As the link_caps array is efficient for <speed,duplex> lookups, implement a function for speed/duplex lookups that matches a given mask. This replicates to some extent the phy_lookup_settings() behaviour, matching full link_capabilities instead of a single linkmode. phy.c's phy_santize_settings() and phylink's phylink_ethtool_ksettings_set() performs such lookup using the phy_settings table, but are only interested in the actual speed/duplex that were matched, rathet than the individual linkmode. Similar to phy_lookup_settings(), the newly introduced phy_caps_lookup() will run through the link_caps[] array by descending speed/duplex order. If the link_capabilities for a given <speed/duplex> tuple intersects the passed linkmodes, we consider that a match. Similar to phy_lookup_settings(), we also allow passing an 'exact' boolean, allowing non-exact match. Here, we MUST always match the linkmodes mask, but we allow matching on lower speed settings. Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> Link: https://patch.msgid.link/20250307173611.129125-8-maxime.chevallier@bootlin.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent dbcd85b commit fc81e25

File tree

4 files changed

+67
-33
lines changed

4 files changed

+67
-33
lines changed

drivers/net/phy/phy-caps.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,8 @@ phy_caps_lookup_by_linkmode(const unsigned long *linkmodes);
5151
const struct link_capabilities *
5252
phy_caps_lookup_by_linkmode_rev(const unsigned long *linkmodes, bool fdx_only);
5353

54+
const struct link_capabilities *
55+
phy_caps_lookup(int speed, unsigned int duplex, const unsigned long *supported,
56+
bool exact);
57+
5458
#endif /* __PHY_CAPS_H */

drivers/net/phy/phy.c

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -213,25 +213,6 @@ int phy_aneg_done(struct phy_device *phydev)
213213
}
214214
EXPORT_SYMBOL(phy_aneg_done);
215215

216-
/**
217-
* phy_find_valid - find a PHY setting that matches the requested parameters
218-
* @speed: desired speed
219-
* @duplex: desired duplex
220-
* @supported: mask of supported link modes
221-
*
222-
* Locate a supported phy setting that is, in priority order:
223-
* - an exact match for the specified speed and duplex mode
224-
* - a match for the specified speed, or slower speed
225-
* - the slowest supported speed
226-
* Returns the matched phy_setting entry, or %NULL if no supported phy
227-
* settings were found.
228-
*/
229-
static const struct phy_setting *
230-
phy_find_valid(int speed, int duplex, unsigned long *supported)
231-
{
232-
return phy_lookup_setting(speed, duplex, supported, false);
233-
}
234-
235216
/**
236217
* phy_supported_speeds - return all speeds currently supported by a phy device
237218
* @phy: The phy device to return supported speeds of.
@@ -274,13 +255,14 @@ EXPORT_SYMBOL(phy_check_valid);
274255
*/
275256
static void phy_sanitize_settings(struct phy_device *phydev)
276257
{
277-
const struct phy_setting *setting;
258+
const struct link_capabilities *c;
259+
260+
c = phy_caps_lookup(phydev->speed, phydev->duplex, phydev->supported,
261+
false);
278262

279-
setting = phy_find_valid(phydev->speed, phydev->duplex,
280-
phydev->supported);
281-
if (setting) {
282-
phydev->speed = setting->speed;
283-
phydev->duplex = setting->duplex;
263+
if (c) {
264+
phydev->speed = c->speed;
265+
phydev->duplex = c->duplex;
284266
} else {
285267
/* We failed to find anything (no supported speeds?) */
286268
phydev->speed = SPEED_UNKNOWN;

drivers/net/phy/phy_caps.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,53 @@ phy_caps_lookup_by_linkmode_rev(const unsigned long *linkmodes, bool fdx_only)
170170
return NULL;
171171
}
172172

173+
/**
174+
* phy_caps_lookup() - Lookup capabilities by speed/duplex that matches a mask
175+
* @speed: Speed to match
176+
* @duplex: Duplex to match
177+
* @supported: Mask of linkmodes to match
178+
* @exact: Perform an exact match or not.
179+
*
180+
* Lookup a link_capabilities entry that intersect the supported linkmodes mask,
181+
* and that matches the passed speed and duplex.
182+
*
183+
* When @exact is set, an exact match is performed on speed and duplex, meaning
184+
* that if the linkmodes for the given speed and duplex intersect the supported
185+
* mask, this capability is returned, otherwise we don't have a match and return
186+
* NULL.
187+
*
188+
* When @exact is not set, we return either an exact match, or matching capabilities
189+
* at lower speed, or the lowest matching speed, or NULL.
190+
*
191+
* Returns: a matched link_capabilities according to the above process, NULL
192+
* otherwise.
193+
*/
194+
const struct link_capabilities *
195+
phy_caps_lookup(int speed, unsigned int duplex, const unsigned long *supported,
196+
bool exact)
197+
{
198+
const struct link_capabilities *lcap, *last = NULL;
199+
200+
for_each_link_caps_desc_speed(lcap) {
201+
if (linkmode_intersects(lcap->linkmodes, supported)) {
202+
last = lcap;
203+
/* exact match on speed and duplex*/
204+
if (lcap->speed == speed && lcap->duplex == duplex) {
205+
return lcap;
206+
} else if (!exact) {
207+
if (lcap->speed <= speed)
208+
return lcap;
209+
}
210+
}
211+
}
212+
213+
if (!exact)
214+
return last;
215+
216+
return NULL;
217+
}
218+
EXPORT_SYMBOL_GPL(phy_caps_lookup);
219+
173220
/**
174221
* phy_caps_linkmode_max_speed() - Clamp a linkmodes set to a max speed
175222
* @max_speed: Speed limit for the linkmode set

drivers/net/phy/phylink.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/timer.h>
2121
#include <linux/workqueue.h>
2222

23+
#include "phy-caps.h"
2324
#include "sfp.h"
2425
#include "swphy.h"
2526

@@ -2852,8 +2853,8 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
28522853
const struct ethtool_link_ksettings *kset)
28532854
{
28542855
__ETHTOOL_DECLARE_LINK_MODE_MASK(support);
2856+
const struct link_capabilities *c;
28552857
struct phylink_link_state config;
2856-
const struct phy_setting *s;
28572858

28582859
ASSERT_RTNL();
28592860

@@ -2896,23 +2897,23 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
28962897
/* Autonegotiation disabled, select a suitable speed and
28972898
* duplex.
28982899
*/
2899-
s = phy_lookup_setting(kset->base.speed, kset->base.duplex,
2900-
pl->supported, false);
2901-
if (!s)
2900+
c = phy_caps_lookup(kset->base.speed, kset->base.duplex,
2901+
pl->supported, false);
2902+
if (!c)
29022903
return -EINVAL;
29032904

29042905
/* If we have a fixed link, refuse to change link parameters.
29052906
* If the link parameters match, accept them but do nothing.
29062907
*/
29072908
if (pl->req_link_an_mode == MLO_AN_FIXED) {
2908-
if (s->speed != pl->link_config.speed ||
2909-
s->duplex != pl->link_config.duplex)
2909+
if (c->speed != pl->link_config.speed ||
2910+
c->duplex != pl->link_config.duplex)
29102911
return -EINVAL;
29112912
return 0;
29122913
}
29132914

2914-
config.speed = s->speed;
2915-
config.duplex = s->duplex;
2915+
config.speed = c->speed;
2916+
config.duplex = c->duplex;
29162917
break;
29172918

29182919
case AUTONEG_ENABLE:

0 commit comments

Comments
 (0)