summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2020-01-22 10:18:02 +0000
committerRussell King <rmk+kernel@armlinux.org.uk>2020-03-30 12:39:41 +0100
commit7d1891db3be8f25ebd50082e36ff7d9a46965e61 (patch)
tree869ea89e5fb4b7272d15417ce2472f4580e0191a
parente7a5639f35055da272e21b4bed9492a2ed7270db (diff)
net: phylink: improve initial mac configuration
Improve the initial MAC configuration so we get a configuration which more represents the final operating mode, in particular with respect to the flow control settings. We do this by: 1) more fully initialising our phy state, so we can use this as the initial state for PHY based connections. 2) reading the fixed link state. 3) ensuring that in-band mode has sane pause settings for SGMII vs 802.3z negotiation modes. In all three cases, we ensure that state->link is false, just in case any MAC drivers have other ideas by mis-using this member, and we also take account of manual pause mode configuration at this point. This avoids MLO_PAUSE_AN being seen in mac_config() when operating in PHY, fixed mode or inband SGMII mode, thereby giving cleaner semantics to the pause flags. As a result of this, the pause flags now indicate in a mode-independent way what is required from a mac_config() implementation. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/net/phy/phylink.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 3b45f9aa6fbe..a5ca934ea12e 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -431,6 +431,35 @@ static void phylink_get_fixed_state(struct phylink *pl,
phylink_resolve_flow(state);
}
+static void phylink_mac_initial_config(struct phylink *pl)
+{
+ struct phylink_link_state link_state;
+
+ switch (pl->cur_link_an_mode) {
+ case MLO_AN_PHY:
+ link_state = pl->phy_state;
+ break;
+
+ case MLO_AN_FIXED:
+ phylink_get_fixed_state(pl, &link_state);
+ break;
+
+ case MLO_AN_INBAND:
+ link_state = pl->link_config;
+ if (link_state.interface == PHY_INTERFACE_MODE_SGMII)
+ link_state.pause = MLO_PAUSE_NONE;
+ break;
+
+ default: /* can't happen */
+ return;
+ }
+
+ link_state.link = false;
+
+ phylink_apply_manual_flow(pl, &link_state);
+ phylink_mac_config(pl, &link_state);
+}
+
static const char *phylink_pause_to_str(int pause)
{
switch (pause & MLO_PAUSE_TXRX_MASK) {
@@ -785,6 +814,9 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
mutex_lock(&pl->state_mutex);
pl->phydev = phy;
pl->phy_state.interface = interface;
+ pl->phy_state.pause = MLO_PAUSE_NONE;
+ pl->phy_state.speed = SPEED_UNKNOWN;
+ pl->phy_state.duplex = DUPLEX_UNKNOWN;
linkmode_copy(pl->supported, supported);
linkmode_copy(pl->link_config.advertising, config.advertising);
@@ -1014,7 +1046,7 @@ 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_mac_config(pl, &pl->link_config);
+ phylink_mac_initial_config(pl);
/* Restart autonegotiation if using 802.3z to ensure that the link
* parameters are properly negotiated. This is necessary for DSA
@@ -1832,7 +1864,7 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,
if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
&pl->phylink_disable_state))
- phylink_mac_config(pl, &pl->link_config);
+ phylink_mac_initial_config(pl);
return ret;
}