diff mbox series

[net-next,v3,09/47] net: phylink: Adjust advertisement based on rate adaptation

Message ID 20220715215954.1449214-10-sean.anderson@seco.com (mailing list archive)
State New, archived
Headers show
Series net: dpaa: Convert to phylink | expand

Commit Message

Sean Anderson July 15, 2022, 9:59 p.m. UTC
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 <sean.anderson@seco.com>
---

Changes in v3:
- New

 drivers/net/phy/phylink.c | 41 ++++++++++++++++++++++++++++++++++++---
 include/linux/phylink.h   |  6 +++++-
 2 files changed, 43 insertions(+), 4 deletions(-)
diff mbox series

Patch

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);