diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2017-01-03 18:34:17 +0000 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2017-02-20 10:47:20 +0000 |
commit | 80d54294d168112d793cfb56f4afe3c2ff7e8588 (patch) | |
tree | d83345995ad0c2828ffbb7a7fe625d82b10f13e8 /drivers | |
parent | d8b358f2f1e46ce2ca6140e70284cb7d8961d9f2 (diff) |
phylink: propagate PHY interface mode to MAC driver
Some 10Gigabit PHYs automatically switch the mode of their host
interface depending on their negotiated speed. We need to communicate
this to the MAC driver so the MAC can switch its host interface to
match the PHYs new operating mode. Provide the current PHY interface
mode to the MAC driver.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
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)); } |