diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2020-07-21 14:04:36 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-07-22 01:46:50 +0300 |
commit | 1571e700fd610c39e8b50b0110b1ee9badb2fe6a (patch) | |
tree | beec579c3ff434a1d9e4ef8462b6c94ac0a36f2d /drivers/net/phy/phylink.c | |
parent | 1e1bf14a89c0f5d11b62a8974dc53862e214b131 (diff) | |
download | linux-1571e700fd610c39e8b50b0110b1ee9badb2fe6a.tar.xz |
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.c | 55 |
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); |