summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/phy/phylink.c40
1 files changed, 29 insertions, 11 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 3bf7c5b0b2b3..ff16d4152239 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -242,8 +242,9 @@ static void phylink_mac_config(struct phylink *pl,
const struct phylink_link_state *state)
{
netdev_dbg(pl->netdev,
- "%s: mode=%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n",
+ "%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n",
__func__, phylink_an_mode_str(pl->link_an_mode),
+ phy_modes(state->interface),
phy_speed_to_str(state->speed),
phy_duplex_to_str(state->duplex),
__ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
@@ -264,6 +265,7 @@ static int phylink_get_mac_state(struct phylink *pl, struct phylink_link_state *
linkmode_copy(state->advertising, pl->link_config.advertising);
linkmode_zero(state->lp_advertising);
+ state->interface = pl->link_config.interface;
state->an_enabled = pl->link_config.an_enabled;
state->link = 1;
@@ -344,19 +346,38 @@ static void phylink_resolve(struct work_struct *w)
case MLO_AN_PHY:
link_state = pl->phy_state;
phylink_resolve_flow(pl, &link_state);
+ phylink_mac_config(pl, &link_state);
break;
case MLO_AN_FIXED:
phylink_get_fixed_state(pl, &link_state);
+ phylink_mac_config(pl, &link_state);
break;
case MLO_AN_SGMII:
phylink_get_mac_state(pl, &link_state);
if (pl->phydev) {
+ bool changed = false;
+
link_state.link = link_state.link &&
pl->phy_state.link;
- link_state.pause |= pl->phy_state.pause;
- phylink_resolve_flow(pl, &link_state);
+
+ if (pl->phy_state.interface !=
+ link_state.interface) {
+ link_state.interface = pl->phy_state.interface;
+ changed = true;
+ }
+
+ /* Propagate the flow control from the PHY
+ * to the MAC. Also propagate the interface
+ * if changed.
+ */
+ if (pl->phy_state.link || changed) {
+ link_state.pause |= pl->phy_state.pause;
+ phylink_resolve_flow(pl, &link_state);
+
+ phylink_mac_config(pl, &link_state);
+ }
}
break;
@@ -372,13 +393,6 @@ static void phylink_resolve(struct work_struct *w)
pl->ops->mac_link_down(ndev, pl->link_an_mode);
netdev_info(ndev, "Link is Down\n");
} else {
- /* If we have a PHY, we need the MAC updated with
- * the current link parameters (eg, in SGMII mode,
- * with flow control status.)
- */
- if (pl->phydev)
- phylink_mac_config(pl, &link_state);
-
pl->ops->mac_link_up(ndev, pl->link_an_mode,
pl->phydev);
@@ -414,8 +428,10 @@ struct phylink *phylink_create(struct net_device *ndev, struct device_node *np,
mutex_init(&pl->config_mutex);
INIT_WORK(&pl->resolve, phylink_resolve);
pl->netdev = ndev;
+ pl->phy_state.interface = iface;
pl->link_interface = iface;
pl->link_port = PORT_MII;
+ pl->link_config.interface = iface;
pl->link_config.pause = MLO_PAUSE_AN;
pl->link_config.speed = SPEED_UNKNOWN;
pl->link_config.duplex = DUPLEX_UNKNOWN;
@@ -471,12 +487,14 @@ void phylink_phy_change(struct phy_device *phydev, bool up, bool do_carrier)
pl->phy_state.pause |= MLO_PAUSE_SYM;
if (phydev->asym_pause)
pl->phy_state.pause |= MLO_PAUSE_ASYM;
+ pl->phy_state.interface = phydev->interface;
pl->phy_state.link = up;
mutex_unlock(&pl->state_mutex);
phylink_run_resolve(pl);
- netdev_dbg(pl->netdev, "phy link %s %s/%s\n", up ? "up" : "down",
+ netdev_dbg(pl->netdev, "phy link %s %s/%s/%s\n", up ? "up" : "down",
+ phy_modes(phydev->interface),
phy_speed_to_str(phydev->speed),
phy_duplex_to_str(phydev->duplex));
}