[PATCH net-next v3 09/47] net: phylink: Adjust advertisement based on rate adaptation
From: Sean Anderson <hidden>
Date: 2022-07-15 22:01:51
Also in:
linux-arm-kernel, lkml
Subsystem:
ethernet phy library, networking drivers, sff/sfp/sfp+ module support, the rest · Maintainers:
Andrew Lunn, Heiner Kallweit, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Russell King, Linus Torvalds
This adds support for adjusting the advertisement for pause-based rate adaptation. This may result in a lossy link, since the final link settings are not adjusted. Asymmetric pause support is necessary. It would be possible for a MAC supporting only symmetric pause to use pause-based rate adaptation, but only if pause reception was enabled as well. Signed-off-by: Sean Anderson <redacted> --- Changes in v3: - New drivers/net/phy/phylink.c | 41 ++++++++++++++++++++++++++++++++++++--- include/linux/phylink.h | 6 +++++- 2 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index a952cdc7c96e..7fa21941878e 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c@@ -370,13 +370,15 @@ static int phy_interface_speed(phy_interface_t interface, int link_speed) * @linkmodes: ethtool linkmode mask (must be already initialised) * @interface: phy interface mode defined by &typedef phy_interface_t * @mac_capabilities: bitmask of MAC capabilities + * @rate_adaptation: type of rate adaptation being performed * * Set all possible pause, speed and duplex linkmodes in @linkmodes that * are supported by the @interface mode and @mac_capabilities. @linkmodes * must have been initialised previously. */ void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, - unsigned long mac_capabilities) + unsigned long mac_capabilities, + enum rate_adaptation rate_adaptation) { unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
@@ -451,7 +453,38 @@ void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, break; } - phylink_caps_to_linkmodes(linkmodes, caps & mac_capabilities); + caps = caps & mac_capabilities; + + switch (rate_adaptation) { + case RATE_ADAPT_NONE: + break; + case RATE_ADAPT_PAUSE: { + unsigned long adapted_caps; + + /* The mac must support pause for this */ + if (!(caps & MAC_ASYM_PAUSE)) + goto open_loop; + + /* Can't adapt if there's nothing slower */ + if (__fls(caps) <= __fls(MAC_10)) + break; + + adapted_caps = GENMASK(__fls(caps), __fls(MAC_10HD)); + /* We can't use pause frames in half-duplex mode */ + adapted_caps &= ~(MAC_1000HD | MAC_100HD | MAC_10HD); + caps |= adapted_caps; + break; + } + case RATE_ADAPT_CRS: + /* TODO */ + break; + case RATE_ADAPT_OPEN_LOOP: +open_loop: + /* TODO */ + break; + } + + phylink_caps_to_linkmodes(linkmodes, caps); } EXPORT_SYMBOL_GPL(phylink_get_linkmodes);
@@ -473,7 +506,8 @@ void phylink_generic_validate(struct phylink_config *config, phylink_set_port_modes(mask); phylink_set(mask, Autoneg); - phylink_get_linkmodes(mask, state->interface, config->mac_capabilities); + phylink_get_linkmodes(mask, state->interface, config->mac_capabilities, + state->rate_adaptation); linkmode_and(supported, supported, mask); linkmode_and(state->advertising, state->advertising, mask);
@@ -1462,6 +1496,7 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, config.interface = PHY_INTERFACE_MODE_NA; else config.interface = interface; + config.rate_adaptation = phy_get_rate_adaptation(phy, config.interface); ret = phylink_validate(pl, supported, &config); if (ret) {
diff --git a/include/linux/phylink.h b/include/linux/phylink.h
index 30e3fbe19fb4..f990f8eab655 100644
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h@@ -65,6 +65,8 @@ static inline bool phylink_autoneg_inband(unsigned int mode) * @link: true if the link is up. * @an_enabled: true if autonegotiation is enabled/desired. * @an_complete: true if autonegotiation has completed. + * @rate_adaptation: method of throttling @interface_speed to @speed, one of + * RATE_ADAPT_* constants. */ struct phylink_link_state { __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
@@ -74,6 +76,7 @@ struct phylink_link_state { int link_speed; int duplex; int pause; + enum rate_adaptation rate_adaptation; unsigned int link:1; unsigned int an_enabled:1; unsigned int an_complete:1;
@@ -523,7 +526,8 @@ void pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, #endif void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, - unsigned long mac_capabilities); + unsigned long mac_capabilities, + enum rate_adaptation rate_adaptation); void phylink_generic_validate(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state);
--
2.35.1.1320.gc452695387.dirty