You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
4.1 KiB
126 lines
4.1 KiB
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;
|
|
|