openwrt/target/linux/mvebu/patches-4.9/436-phylink-propagate-PHY-i...

127 lines
4.1 KiB
Diff

From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Tue, 3 Jan 2017 18:34:17 +0000
Subject: [PATCH] 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>
---
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -242,8 +242,9 @@ static void phylink_mac_config(struct ph
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
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_
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_
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 ne
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_devic
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));
}
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -27,6 +27,7 @@ enum {
struct phylink_link_state {
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
__ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising);
+ phy_interface_t interface; /* PHY_INTERFACE_xxx */
int speed;
int duplex;
int pause;