Blob Blame History Raw
From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Sat, 15 Feb 2020 15:49:43 +0000
Subject: net: phylink: ensure manual flow control is selected appropriately
Patch-mainline: v5.7-rc1
Git-commit: 2d5fbef0c8070c9f55c7ec937e84f851e9a0bb75
References: bsc#1176447

Split the application of manually controlled flow control modes from
phylink_resolve_flow(), so that we can use alternative providers of
flow control resolution.

We also want to clear the MLO_PAUSE_AN flag when autoneg is disabled,
since flow control can't be negotiated in this circumstance.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
 drivers/net/phy/phylink.c |   46 +++++++++++++++++++++++++++-------------------
 1 file changed, 27 insertions(+), 19 deletions(-)

--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -338,6 +338,18 @@ static int phylink_parse_mode(struct phy
 	return 0;
 }
 
+static void phylink_apply_manual_flow(struct phylink *pl,
+				      struct phylink_link_state *state)
+{
+	/* If autoneg is disabled, pause AN is also disabled */
+	if (!state->an_enabled)
+		state->pause &= ~MLO_PAUSE_AN;
+
+	/* Manual configuration of pause modes */
+	if (!(pl->link_config.pause & MLO_PAUSE_AN))
+		state->pause = pl->link_config.pause;
+}
+
 static void phylink_mac_config(struct phylink *pl,
 			       const struct phylink_link_state *state)
 {
@@ -407,25 +419,20 @@ static void phylink_resolve_flow(struct
 				 struct phylink_link_state *state)
 {
 	int new_pause = 0;
+	int pause = 0;
 
-	if (pl->link_config.pause & MLO_PAUSE_AN) {
-		int pause = 0;
-
-		if (phylink_test(pl->link_config.advertising, Pause))
-			pause |= MLO_PAUSE_SYM;
-		if (phylink_test(pl->link_config.advertising, Asym_Pause))
-			pause |= MLO_PAUSE_ASYM;
-
-		pause &= state->pause;
-
-		if (pause & MLO_PAUSE_SYM)
-			new_pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
-		else if (pause & MLO_PAUSE_ASYM)
-			new_pause = state->pause & MLO_PAUSE_SYM ?
-				 MLO_PAUSE_TX : MLO_PAUSE_RX;
-	} else {
-		new_pause = pl->link_config.pause & MLO_PAUSE_TXRX_MASK;
-	}
+	if (phylink_test(pl->link_config.advertising, Pause))
+		pause |= MLO_PAUSE_SYM;
+	if (phylink_test(pl->link_config.advertising, Asym_Pause))
+		pause |= MLO_PAUSE_ASYM;
+
+	pause &= state->pause;
+
+	if (pause & MLO_PAUSE_SYM)
+		new_pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
+	else if (pause & MLO_PAUSE_ASYM)
+		new_pause = state->pause & MLO_PAUSE_SYM ?
+			 MLO_PAUSE_TX : MLO_PAUSE_RX;
 
 	state->pause &= ~MLO_PAUSE_TXRX_MASK;
 	state->pause |= new_pause;
@@ -493,6 +500,7 @@ static void phylink_resolve(struct work_
 		case MLO_AN_PHY:
 			link_state = pl->phy_state;
 			phylink_resolve_flow(pl, &link_state);
+			phylink_apply_manual_flow(pl, &link_state);
 			phylink_mac_config_up(pl, &link_state);
 			break;
 
@@ -517,6 +525,7 @@ static void phylink_resolve(struct work_
 				 * the pause mode bits. */
 				link_state.pause |= pl->phy_state.pause;
 				phylink_resolve_flow(pl, &link_state);
+				phylink_apply_manual_flow(pl, &link_state);
 				phylink_mac_config(pl, &link_state);
 			}
 			break;
@@ -1002,7 +1011,6 @@ void phylink_start(struct phylink *pl)
 	 * a fixed-link to start with the correct parameters, and also
 	 * ensures that we set the appropriate advertisement for Serdes links.
 	 */
-	phylink_resolve_flow(pl, &pl->link_config);
 	phylink_mac_config(pl, &pl->link_config);
 
 	/* Restart autonegotiation if using 802.3z to ensure that the link