Message ID | 20250228145540.2209551-4-maxime.chevallier@bootlin.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | net: phy: Rework linkmodes handling in a dedicated file | expand |
On Fri, Feb 28, 2025 at 03:55:28PM +0100, Maxime Chevallier wrote: > Use the newly introduced link_capabilities array to derive the list of > possible speeds when given a combination of linkmodes. As > link_capabilities is indexed by speed, we don't have to iterate the > whole phy_settings array. > > Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> > --- > drivers/net/phy/phy-caps.h | 3 +++ > drivers/net/phy/phy-core.c | 15 --------------- > drivers/net/phy/phy.c | 3 ++- > drivers/net/phy/phy_caps.c | 27 +++++++++++++++++++++++++++ > include/linux/phy.h | 2 -- > 5 files changed, 32 insertions(+), 18 deletions(-) > > diff --git a/drivers/net/phy/phy-caps.h b/drivers/net/phy/phy-caps.h > index 846d483269f6..f8cdfdb09242 100644 > --- a/drivers/net/phy/phy-caps.h > +++ b/drivers/net/phy/phy-caps.h > @@ -41,4 +41,7 @@ struct link_capabilities { > > void phy_caps_init(void); > > +size_t phy_caps_speeds(unsigned int *speeds, size_t size, > + unsigned long *linkmodes); > + > #endif /* __PHY_CAPS_H */ > diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c > index b1c1670de23b..8533e57c3500 100644 > --- a/drivers/net/phy/phy-core.c > +++ b/drivers/net/phy/phy-core.c > @@ -339,21 +339,6 @@ phy_lookup_setting(int speed, int duplex, const unsigned long *mask, bool exact) > } > EXPORT_SYMBOL_GPL(phy_lookup_setting); > > -size_t phy_speeds(unsigned int *speeds, size_t size, > - unsigned long *mask) > -{ > - size_t count; > - int i; > - > - for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++) > - if (settings[i].bit < __ETHTOOL_LINK_MODE_MASK_NBITS && > - test_bit(settings[i].bit, mask) && > - (count == 0 || speeds[count - 1] != settings[i].speed)) > - speeds[count++] = settings[i].speed; > - > - return count; > -} > - > static void __set_linkmode_max_speed(u32 max_speed, unsigned long *addr) > { > const struct phy_setting *p; > diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c > index 16ffc00b419c..3128df03feda 100644 > --- a/drivers/net/phy/phy.c > +++ b/drivers/net/phy/phy.c > @@ -37,6 +37,7 @@ > #include <net/sock.h> > > #include "phylib-internal.h" > +#include "phy-caps.h" > > #define PHY_STATE_TIME HZ > > @@ -245,7 +246,7 @@ unsigned int phy_supported_speeds(struct phy_device *phy, > unsigned int *speeds, > unsigned int size) > { > - return phy_speeds(speeds, size, phy->supported); > + return phy_caps_speeds(speeds, size, phy->supported); > } > > /** > diff --git a/drivers/net/phy/phy_caps.c b/drivers/net/phy/phy_caps.c > index 367ca7110ddc..e5c716365b36 100644 > --- a/drivers/net/phy/phy_caps.c > +++ b/drivers/net/phy/phy_caps.c > @@ -76,3 +76,30 @@ void phy_caps_init(void) > __set_bit(i, link_caps[capa].linkmodes); > } > } > + > +/** > + * phy_caps_speeds() - Fill an array of supported SPEED_* values for given modes > + * @speeds: Output array to store the speeds list into > + * @size: Size of the output array > + * @linkmodes: Linkmodes to get the speeds from > + * > + * Fills the speeds array with all possible speeds that can be achieved with > + * the specified linkmodes. > + * > + * Returns: The number of speeds filled into the array. If the input array isn't > + * big enough to store all speeds, fill it as much as possible. > + */ > +size_t phy_caps_speeds(unsigned int *speeds, size_t size, > + unsigned long *linkmodes) > +{ > + size_t count; > + int capa; > + > + for (capa = 0, count = 0; capa < __LINK_CAPA_MAX && count < size; capa++) { > + if (linkmode_intersects(link_caps[capa].linkmodes, linkmodes) && > + (count == 0 || speeds[count - 1] != link_caps[capa].speed)) > + speeds[count++] = link_caps[capa].speed; > + } Having looked at several of these patches, there's a common pattern emerging, which is we're walking over link_caps in either ascending speed order or descending speed order. So I wonder whether it would make sense to have: #define for_each_link_caps_asc_speed(cap) \ for (cap = link_caps; cap < &link_caps[__LINK_CAPA_MAX]; cap++) #define for_each_link_caps_desc_speed(cap) \ for (cap = &link_caps[__LINK_CAPA_MAX - 1]; cap >= link_caps; cap--) for where iterating over in speed order is important. E.g. this would make the above: struct link_capabilities *lcap; for_each_link_caps_asc_speed(lcap) if (linkmode_intersects(lcap->linkmodes, linkmodes) && (count == 0 || speeds[count - 1] != lcap->speed)) { speeds[count++] = lcap->speed; if (count >= size) break; } which helps to make it explicit that speeds[] is in ascending value order.
Hi Russell, On Fri, 28 Feb 2025 16:10:35 +0000 "Russell King (Oracle)" <linux@armlinux.org.uk> wrote: > On Fri, Feb 28, 2025 at 03:55:28PM +0100, Maxime Chevallier wrote: > > Use the newly introduced link_capabilities array to derive the list of > > possible speeds when given a combination of linkmodes. As > > link_capabilities is indexed by speed, we don't have to iterate the > > whole phy_settings array. > > > > Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> [...] > > +/** > > + * phy_caps_speeds() - Fill an array of supported SPEED_* values for given modes > > + * @speeds: Output array to store the speeds list into > > + * @size: Size of the output array > > + * @linkmodes: Linkmodes to get the speeds from > > + * > > + * Fills the speeds array with all possible speeds that can be achieved with > > + * the specified linkmodes. > > + * > > + * Returns: The number of speeds filled into the array. If the input array isn't > > + * big enough to store all speeds, fill it as much as possible. > > + */ > > +size_t phy_caps_speeds(unsigned int *speeds, size_t size, > > + unsigned long *linkmodes) > > +{ > > + size_t count; > > + int capa; > > + > > + for (capa = 0, count = 0; capa < __LINK_CAPA_MAX && count < size; capa++) { > > + if (linkmode_intersects(link_caps[capa].linkmodes, linkmodes) && > > + (count == 0 || speeds[count - 1] != link_caps[capa].speed)) > > + speeds[count++] = link_caps[capa].speed; > > + } > > Having looked at several of these patches, there's a common pattern > emerging, which is we're walking over link_caps in either ascending > speed order or descending speed order. So I wonder whether it would > make sense to have: > > #define for_each_link_caps_asc_speed(cap) \ > for (cap = link_caps; cap < &link_caps[__LINK_CAPA_MAX]; cap++) > #define for_each_link_caps_desc_speed(cap) \ > for (cap = &link_caps[__LINK_CAPA_MAX - 1]; cap >= link_caps; cap--) > > for where iterating over in speed order is important. E.g. this would > make the above: > > struct link_capabilities *lcap; > > for_each_link_caps_asc_speed(lcap) > if (linkmode_intersects(lcap->linkmodes, linkmodes) && > (count == 0 || speeds[count - 1] != lcap->speed)) { > speeds[count++] = lcap->speed; > if (count >= size) > break; > } > > which helps to make it explicit that speeds[] is in ascending value > order. That makes a lot of sense indeed, I will definitely add that. Thanks a lot for the review, Maxime
diff --git a/drivers/net/phy/phy-caps.h b/drivers/net/phy/phy-caps.h index 846d483269f6..f8cdfdb09242 100644 --- a/drivers/net/phy/phy-caps.h +++ b/drivers/net/phy/phy-caps.h @@ -41,4 +41,7 @@ struct link_capabilities { void phy_caps_init(void); +size_t phy_caps_speeds(unsigned int *speeds, size_t size, + unsigned long *linkmodes); + #endif /* __PHY_CAPS_H */ diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index b1c1670de23b..8533e57c3500 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -339,21 +339,6 @@ phy_lookup_setting(int speed, int duplex, const unsigned long *mask, bool exact) } EXPORT_SYMBOL_GPL(phy_lookup_setting); -size_t phy_speeds(unsigned int *speeds, size_t size, - unsigned long *mask) -{ - size_t count; - int i; - - for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++) - if (settings[i].bit < __ETHTOOL_LINK_MODE_MASK_NBITS && - test_bit(settings[i].bit, mask) && - (count == 0 || speeds[count - 1] != settings[i].speed)) - speeds[count++] = settings[i].speed; - - return count; -} - static void __set_linkmode_max_speed(u32 max_speed, unsigned long *addr) { const struct phy_setting *p; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 16ffc00b419c..3128df03feda 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -37,6 +37,7 @@ #include <net/sock.h> #include "phylib-internal.h" +#include "phy-caps.h" #define PHY_STATE_TIME HZ @@ -245,7 +246,7 @@ unsigned int phy_supported_speeds(struct phy_device *phy, unsigned int *speeds, unsigned int size) { - return phy_speeds(speeds, size, phy->supported); + return phy_caps_speeds(speeds, size, phy->supported); } /** diff --git a/drivers/net/phy/phy_caps.c b/drivers/net/phy/phy_caps.c index 367ca7110ddc..e5c716365b36 100644 --- a/drivers/net/phy/phy_caps.c +++ b/drivers/net/phy/phy_caps.c @@ -76,3 +76,30 @@ void phy_caps_init(void) __set_bit(i, link_caps[capa].linkmodes); } } + +/** + * phy_caps_speeds() - Fill an array of supported SPEED_* values for given modes + * @speeds: Output array to store the speeds list into + * @size: Size of the output array + * @linkmodes: Linkmodes to get the speeds from + * + * Fills the speeds array with all possible speeds that can be achieved with + * the specified linkmodes. + * + * Returns: The number of speeds filled into the array. If the input array isn't + * big enough to store all speeds, fill it as much as possible. + */ +size_t phy_caps_speeds(unsigned int *speeds, size_t size, + unsigned long *linkmodes) +{ + size_t count; + int capa; + + for (capa = 0, count = 0; capa < __LINK_CAPA_MAX && count < size; capa++) { + if (linkmode_intersects(link_caps[capa].linkmodes, linkmodes) && + (count == 0 || speeds[count - 1] != link_caps[capa].speed)) + speeds[count++] = link_caps[capa].speed; + } + + return count; +} diff --git a/include/linux/phy.h b/include/linux/phy.h index 7bfbae51070a..5749aad96862 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1322,8 +1322,6 @@ struct phy_setting { const struct phy_setting * phy_lookup_setting(int speed, int duplex, const unsigned long *mask, bool exact); -size_t phy_speeds(unsigned int *speeds, size_t size, - unsigned long *mask); /** * phy_is_started - Convenience function to check whether PHY is started
Use the newly introduced link_capabilities array to derive the list of possible speeds when given a combination of linkmodes. As link_capabilities is indexed by speed, we don't have to iterate the whole phy_settings array. Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> --- drivers/net/phy/phy-caps.h | 3 +++ drivers/net/phy/phy-core.c | 15 --------------- drivers/net/phy/phy.c | 3 ++- drivers/net/phy/phy_caps.c | 27 +++++++++++++++++++++++++++ include/linux/phy.h | 2 -- 5 files changed, 32 insertions(+), 18 deletions(-)