summaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/phylink.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2020-07-21 13:04:36 +0200
committerDavid S. Miller <davem@davemloft.net>2020-07-22 00:46:50 +0200
commit1571e700fd610c39e8b50b0110b1ee9badb2fe6a (patch)
treebeec579c3ff434a1d9e4ef8462b6c94ac0a36f2d /drivers/net/phy/phylink.c
parentnet: phylink: simplify fixed-link case for ksettings_set method (diff)
downloadlinux-1571e700fd610c39e8b50b0110b1ee9badb2fe6a.tar.xz
linux-1571e700fd610c39e8b50b0110b1ee9badb2fe6a.zip
net: phylink: in-band pause mode advertisement update for PCS
Re-code the pause in-band advertisement update in light of the addition of PCS support, so that we perform the minimum required; only the PCS configuration function needs to be called in this case, followed by the request to trigger a restart of negotiation if the programmed advertisement changed. We need to change the pcs_config() signature to pass whether resolved pause should be passed to the MAC for setups such as mvneta and mvpp2 where doing so overrides the MAC manual flow controls. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/phylink.c')
-rw-r--r--drivers/net/phy/phylink.c55
1 files changed, 51 insertions, 4 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 452d509803ca..84a426401102 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -441,7 +441,9 @@ static void phylink_pcs_config(struct phylink *pl, bool force_restart,
if (pl->pcs_ops && pl->pcs_ops->pcs_config(pl->config,
pl->cur_link_an_mode,
state->interface,
- state->advertising))
+ state->advertising,
+ !!(pl->link_config.pause &
+ MLO_PAUSE_AN)))
restart = true;
phylink_mac_config(pl, state);
@@ -450,6 +452,49 @@ static void phylink_pcs_config(struct phylink *pl, bool force_restart,
phylink_mac_pcs_an_restart(pl);
}
+/*
+ * Reconfigure for a change of inband advertisement.
+ * If we have a separate PCS, we only need to call its pcs_config() method,
+ * and then restart AN if it indicates something changed. Otherwise, we do
+ * the full MAC reconfiguration.
+ */
+static int phylink_change_inband_advert(struct phylink *pl)
+{
+ int ret;
+
+ if (test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state))
+ return 0;
+
+ if (!pl->pcs_ops) {
+ /* Legacy method */
+ phylink_mac_config(pl, &pl->link_config);
+ phylink_mac_pcs_an_restart(pl);
+ return 0;
+ }
+
+ phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__,
+ phylink_an_mode_str(pl->cur_link_an_mode),
+ phy_modes(pl->link_config.interface),
+ __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising,
+ pl->link_config.pause);
+
+ /* Modern PCS-based method; update the advert at the PCS, and
+ * restart negotiation if the pcs_config() helper indicates that
+ * the programmed advertisement has changed.
+ */
+ ret = pl->pcs_ops->pcs_config(pl->config, pl->cur_link_an_mode,
+ pl->link_config.interface,
+ pl->link_config.advertising,
+ !!(pl->link_config.pause & MLO_PAUSE_AN));
+ if (ret < 0)
+ return ret;
+
+ if (ret > 0)
+ phylink_mac_pcs_an_restart(pl);
+
+ return 0;
+}
+
static void phylink_mac_pcs_get_state(struct phylink *pl,
struct phylink_link_state *state)
{
@@ -1524,9 +1569,11 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
config->pause = pause_state;
- if (!pl->phydev && !test_bit(PHYLINK_DISABLE_STOPPED,
- &pl->phylink_disable_state))
- phylink_pcs_config(pl, true, &pl->link_config);
+ /* Update our in-band advertisement, triggering a renegotiation if
+ * the advertisement changed.
+ */
+ if (!pl->phydev)
+ phylink_change_inband_advert(pl);
mutex_unlock(&pl->state_mutex);