OSDN Git Service

net: phylink: improve initial mac configuration
authorRussell King <rmk+kernel@armlinux.org.uk>
Sat, 15 Feb 2020 15:50:03 +0000 (15:50 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 17 Feb 2020 03:39:45 +0000 (19:39 -0800)
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>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/phylink.c

index ab72bd1..2899fbe 100644 (file)
@@ -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) {
@@ -779,6 +808,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);
 
@@ -1008,7 +1040,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
@@ -1826,7 +1858,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;
 }