diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/phy/phylink.c | 40 |
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)); } |