summaryrefslogtreecommitdiff
path: root/target/linux/mvebu/patches-4.9/436-phylink-propagate-PHY-interface-mode-to-MAC-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mvebu/patches-4.9/436-phylink-propagate-PHY-interface-mode-to-MAC-driver.patch')
-rw-r--r--target/linux/mvebu/patches-4.9/436-phylink-propagate-PHY-interface-mode-to-MAC-driver.patch126
1 files changed, 126 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-4.9/436-phylink-propagate-PHY-interface-mode-to-MAC-driver.patch b/target/linux/mvebu/patches-4.9/436-phylink-propagate-PHY-interface-mode-to-MAC-driver.patch
new file mode 100644
index 0000000..9b872b8
--- /dev/null
+++ b/target/linux/mvebu/patches-4.9/436-phylink-propagate-PHY-interface-mode-to-MAC-driver.patch
@@ -0,0 +1,126 @@
+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;